package com.ruoyi.business.customer.service.impl;


import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.google.common.collect.Maps;
import com.ruoyi.business.base.JoBaseServiceImpl;
import com.ruoyi.business.base.PageParam;
import com.ruoyi.business.core.domain.DivisionsCode;
import com.ruoyi.business.core.domain.vo.DivisionsCodeAllVo;
import com.ruoyi.business.core.service.DivisionsCodeService;
import com.ruoyi.business.customer.domain.*;
import com.ruoyi.business.customer.domain.dto.JbCustomerDto;
import com.ruoyi.business.customer.domain.dto.JbCustomerListDto;
import com.ruoyi.business.customer.domain.dto.JbCustomerTransferDto;
import com.ruoyi.business.customer.domain.dto.JbCustomerUpdateDto;
import com.ruoyi.business.customer.domain.vo.*;
import com.ruoyi.business.customer.mapper.JbCustomerMapper;
import com.ruoyi.business.customer.service.*;
import com.ruoyi.business.goods.domain.JbCropVariety;
import com.ruoyi.business.goods.domain.JbProduct;
import com.ruoyi.business.goods.service.JbCropVarietyService;
import com.ruoyi.business.goods.service.JbProductService;
import com.ruoyi.business.order.domain.JbOrder;
import com.ruoyi.business.order.domain.JbRefund;
import com.ruoyi.business.order.service.JbOrderService;
import com.ruoyi.business.order.service.JbRefundService;
import com.ruoyi.business.rule.domain.JbCustomerNumberContentJson;
import com.ruoyi.business.rule.domain.JbDeptHighseasRulesJson;
import com.ruoyi.business.rule.domain.JbRules;
import com.ruoyi.business.rule.domain.JbdeptHighseasAllocationRulesJson;
import com.ruoyi.business.rule.service.JbRulesService;
import com.ruoyi.business.sundry.domain.JbBusinessOperRecord;
import com.ruoyi.business.sundry.service.JbBusinessOperRecordService;
import com.ruoyi.business.sundry.service.SysDataScopeFactoryService;
import com.ruoyi.common.constant.Constants;
import com.ruoyi.common.core.domain.entity.SysDept;
import com.ruoyi.common.core.domain.entity.SysDictData;
import com.ruoyi.common.core.domain.entity.SysUser;
import com.ruoyi.common.core.domain.entity.SysUserVo;
import com.ruoyi.common.core.domain.model.LoginUser;
import com.ruoyi.common.enums.BusinessErrorEnum;
import com.ruoyi.common.enums.BusinessOperModule;
import com.ruoyi.common.enums.DesensitizedType;
import com.ruoyi.common.exception.ServiceException;
import com.ruoyi.common.utils.ChineseCharacterUtil;
import com.ruoyi.common.utils.DateUtils;
import com.ruoyi.common.utils.ServletUtils;
import com.ruoyi.common.utils.StringUtils;
import com.ruoyi.system.mapper.SysDeptMapper;
import com.ruoyi.system.service.ISysDictDataService;
import com.ruoyi.system.service.impl.SysDeptServiceImpl;
import com.ruoyi.system.service.impl.SysUserServiceImpl;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.compress.utils.Lists;
import org.apache.commons.lang3.ObjectUtils;
import org.apache.logging.log4j.util.Strings;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.math.BigDecimal;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.*;
import java.util.function.Function;
import java.util.stream.Collectors;

import static com.ruoyi.common.utils.SecurityUtils.getLoginUser;
import static com.ruoyi.common.utils.SecurityUtils.getUserId;

/**
 * 客户Service业务层处理
 *
 * @author ruoyi
 * @date 2024-10-11
 */
@Service
@Slf4j
public class JbCustomerServiceImpl
        extends JoBaseServiceImpl<JbCustomerMapper, JbCustomer>
        implements JbCustomerService
{
    @Autowired
    private JbOpportunityService jbOpportunityService;
    @Autowired
    private JbCustomerUserService jbCustomerUserService;
    @Autowired
    private JbCustomerCropStructureService jbCustomerCropStructureService;
    @Autowired
    private JbFollowupRecordService jbFollowupRecordService;
    @Autowired
    private SysUserServiceImpl sysUserService;
    @Autowired
    private SysDeptServiceImpl sysDeptService;
    @Autowired
    private JbBusinessOperRecordService jbBusinessOperRecordService;
    @Autowired
    private JbRulesService jbRulesService;
    @Autowired
    private DivisionsCodeService divisionsCodeService;
    @Autowired
    private JbOrderService jbOrderService;
    @Autowired
    private JbCropVarietyService jbCropVarietyService;
    @Autowired
    private JbOpportunityPollingService jbOpportunityPollingService;
    @Autowired
    private JbFavoriteTableService jbFavoriteTableService;
    @Autowired
    private JbRefundService jbRefundService;
    @Autowired
    private JbProductService jbProductService;
    @Autowired
    private JbCustomerFieldService jbCustomerFieldService;
    @Autowired
    private JbCustomerFastSearchService jbCustomerFastSearchService;
    @Autowired
    private SysDeptMapper sysDeptMapper;
    @Autowired
    private ISysDictDataService sysDictDataService;
    @Autowired
    private SysDataScopeFactoryService sysDataScopeFactoryService;

    @Override
    @Transactional
    public Long saveInfo(JbCustomerDto jbCustomerDto)
    {
        // 验证手机号是否存
        //TODO 2025年2月18日17:41:04 校验放开  验证手机号，在同一个事业部能是否存在。
        isPhoneExist(jbCustomerDto);
        // 验证业务人员的客户数量，和客户类型是否达到上限
        isCustomerNumber(jbCustomerDto);
        JbCustomer jbCustomer = new JbCustomer();
        BeanUtils.copyProperties(jbCustomerDto, jbCustomer);
        if (ObjectUtils.isNotEmpty(jbCustomerDto.getFollowupRecords()))
        {
            // 更新客户的最后跟进时间
//            jbCustomer.setLatestFollowupTime(jbCustomerDto.getFollowupRecords().getFollowupTime());
        }
        jbCustomer.setCustomerCode(getCustomerCode());
        jbCustomer.setCustomerNamePinyin(ChineseCharacterUtil.getUpperCase(jbCustomer.getCustomerName(), true));
        this.save(jbCustomer);
        // 记录客户和用户关系
        LoginUser loginUser = getLoginUser();
        JbCustomerUser customerUser = new JbCustomerUser();
        customerUser.setCustomerId(jbCustomer.getId());
        customerUser.setUserId(jbCustomerDto.getBusinessManagerId());
        jbCustomerUserService.save(customerUser);
        if (ObjectUtils.isNotEmpty(jbCustomerDto.getCropStructuresList()))
        {
            // 作物结构或者销售情况添加
            List<JbCustomerCropStructure> cropStructuresList = jbCustomerDto.getCropStructuresList();
            cropStructuresList.forEach(a -> a.setCustomerId(jbCustomer.getId()));
            jbCustomerCropStructureService.saveBatch(cropStructuresList);

        }
        if (ObjectUtils.isNotEmpty(jbCustomerDto.getFollowupRecords()))
        {
            // 跟进任务
            jbCustomerDto.getFollowupRecords().setCustomerId(jbCustomer.getId());
            jbCustomerDto.getFollowupRecords().setDataType(Constants.PUBLIC_NUMBER_0);
            jbCustomerDto.getFollowupRecords().setTaskStatus(Constants.JBFOLLOWUPRECORD_TASKSTATUS_1001);
            jbFollowupRecordService.save(jbCustomerDto.getFollowupRecords());
        }
        if (ObjectUtils.isNotEmpty(jbCustomer.getOpportunityId()))
        {
            // 表示从商机转的客户，则更新商机的状态
            JbOpportunity jbOpportunity = new JbOpportunity();
            jbOpportunity.setId(jbCustomer.getOpportunityId());
            jbOpportunity.setDistributionStatus(Constants.PUBLIC_NUMBER_0.longValue());
            jbOpportunity.setCustomerFlag(Constants.PUBLIC_NUMBER_0.toString());
            jbOpportunityService.updateById(jbOpportunity);
            // 去现场要求转移后就删除
            jbOpportunityService.removeById(jbCustomer.getOpportunityId());
        }
        // setBusinessOperRecord(jbCustomer, Constants.PUBLIC_NUMBER_1);
        return jbCustomer.getId();
    }

    /**
     * 新增，删除时验证业务经理的客户数量，和客户类型的数量是否到上限。
     *
     * @param jbCustomerDto
     */
    private void isCustomerNumber(JbCustomer jbCustomerDto)
    {
        JbRules jbRules = jbRulesService.getOne(Wrappers.lambdaQuery(JbRules.class).eq(JbRules::getRulesCode, Constants.DEPT_HIGHSEAS_ALLOCATION));
        List<JbCustomer> jbCustomerList = Lists.newArrayList();
        jbCustomerList.add(jbCustomerDto);
        verifyCustomerNumber(jbRules, jbCustomerDto.getBusinessManagerId(), jbCustomerList);
    }

    /**
     * 验证手机号，在同一个事业部能是否存在。
     *
     * @param jbCustomerDto
     * @return
     */
    private boolean isPhoneExist(JbCustomer jbCustomerDto)
    {
        // 获取
        StringJoiner sql = new StringJoiner(" ").add("""
                   SELECT
                      sd.dept_id,sd.parent_id,sd.ancestors\s
                  FROM
                    sys_user su
                    INNER JOIN sys_dept sd ON su.dept_id = sd.dept_id\s
                  WHERE
                    su.del_flag = 0\s
                    AND sd.del_flag = 0\s
                """);
        sql.add(String.format("AND su.user_id ='%s'", jbCustomerDto.getBusinessManagerId()));
        // 获取业务经理的事业部的id
        List<SysDept> sysDeptList = joSqlUtil.jsonToEntity(baseMapper.findJson(sql.toString()), SysDept.class);
        if (ObjectUtils.isNotEmpty(sysDeptList) && StringUtils.isNotBlank(sysDeptList.get(0).getAncestors()))
        {
            SysDept sysDept = sysDeptList.get(0);
            String ancestors = sysDept.getAncestors();
            String[] split = ancestors.split(",");
            // 取第几层部门
            String s = sysDept.getDeptId().toString();
            if (ObjectUtils.isNotEmpty(split) && split.length > 1)
            {
                s = split[Constants.PUBLIC_NUMBER_1];
            }

            sql = new StringJoiner(" ").add("""
                    SELECT
                        count( jc.id )\s
                    FROM
                        sys_user su
                        INNER JOIN sys_dept sd ON su.dept_id = sd.dept_id
                        INNER JOIN jb_customer jc ON su.user_id = jc.business_manager_id\s
                    WHERE
                        su.del_flag = 0\s
                        AND sd.del_flag = 0\s
                        AND jc.del_flag = 0\s
                    """);
            sql.add(String.format("AND FIND_IN_SET(%s, ancestors )", s));
            sql.add(String.format("AND jc.phone_number = '%s'", jbCustomerDto.getPhoneNumber()));
            sql.add(String.format("AND jc.opportunity_channel = '%s'", jbCustomerDto.getOpportunityChannel()));
            Integer jsonCount = baseMapper.findJsonCount(sql.toString());
            if (jsonCount > 0)
            {
                throw new ServiceException(BusinessErrorEnum.CUSTOMER_PHONE_EXIST_20002);
            }
        }
        return false;
    }

    @Override
    public IPage<JbCustomerListVo> listData(IPage iPage, JbCustomerListDto jbCustomerListDto)
    {

        StringJoiner sql = new StringJoiner(" ").add("""
                SELECT
                	ct.id,
                	ct.customer_name AS customerName,
                	ct.customer_status AS customerStatus,
                	ct.customer_star_level AS customerStarLevel,
                	ct.opportunity_source AS opportunitySource,
                	ct.opportunity_channel AS opportunityChannel,
                	ct.business_manager_id AS businessManagerId,
                	ct.create_by AS createBy,
                	ct.customer_type AS customerType,
                	sub.user_name AS businessManagerName,
                	ct.phone_number AS phoneNumber,
                	ct.latest_followup_time AS latestFollowupTime\s
                FROM
                	jb_customer ct
                	LEFT JOIN sys_user sub ON ct.business_manager_id = sub.user_id\s
                WHERE
                	ct.del_flag = '0'
                """);

        sql.add(joSqlUtil.sqlIf("and ct.business_manager_id='#{businessManagerId}'",
                jbCustomerListDto.getBusinessManagerId()));
        sql.add(joSqlUtil.sqlIf("and ct.customer_status='#{customerStatus}'", jbCustomerListDto.getCustomerStatus()));
        sql.add(joSqlUtil.sqlIf("and ct.customer_type='#{customerType}'", jbCustomerListDto.getCustomerType()));
        sql.add(joSqlUtil.sqlIf("and ct.customer_star_level='#{customerStarLevel}'",
                jbCustomerListDto.getCustomerStarLevel()));
        sql.add(joSqlUtil.sqlIf("and (INSTR(ct.customer_name,'#{keyWords}')>0 or INSTR(ct.phone_number,'#{keyWords}')" +
                ">0 )", jbCustomerListDto.getKeyWords()));
        sql.add(joSqlUtil.sqlIf("and ct.latest_followup_time>='#{startTime}'", jbCustomerListDto.getStartTime()));
        sql.add(joSqlUtil.sqlIf("and ct.latest_followup_time<='#{endTime}'", jbCustomerListDto.getEndTime()));
        sql.add(joSqlUtil.sqlIf("and ct.is_invalid='#{isInvalid}'", jbCustomerListDto.getIsInvalid()));
        sql.add(joSqlUtil.sqlIf("and ct.data_type='#{dataType}'", jbCustomerListDto.getDataType()));
        getRoleData(sql);
        sql.add(" order by ct.top_up desc,ct.id desc");

        String sqlStr = joSqlUtil.sqlJson(sql.toString(), jbCustomerListDto);

        return joSqlUtil.jsonToEntity(baseMapper.pageJson(iPage, sqlStr), JbCustomerListVo.class);
    }

    @Override
    public IPage<JbCustomerListVo> seniorListData(PageParam param, JbCustomerListDto jbCustomerListDto)
    {
        StringJoiner sql = new StringJoiner(" ").add("""
                SELECT
                	ct.id,
                	ct.customer_name AS customerName,
                	ct.customer_status AS customerStatus,
                	ct.customer_star_level AS customerStarLevel,
                	ct.opportunity_source AS opportunitySource,
                	ct.opportunity_channel AS opportunityChannel,
                	ct.business_manager_id AS businessManagerId,
                	ct.local_province AS localProvince,
                	ct.local_city AS localCity,
                	ct.local_county AS localCounty,
                	ct.local_area AS localArea,
                	ct.local_province_name AS localProvinceName,
                	ct.local_city_name AS localCityName,
                	ct.local_county_name AS localCountyName,
                	ct.local_area_name AS localAreaName,
                	ct.detailed_address AS detailedAddress,
                	ct.create_by AS createBy,
                	su.user_name AS createByName,
                	sub.user_name AS businessManagerName,
                	sub.avatar AS avatar,
                	ct.customer_type AS customerType,
                	ct.phone_number AS phoneNumber,
                	ct.top_up_time AS topUpTime,
                	ct.create_time AS createTime,
                	ct.latest_followup_time AS latestFollowupTime,
                	(
                	SELECT
                	IFNULL( DATEDIFF( CURDATE(), ct.latest_followup_time ), 0 )) AS notFollowingDay\s
                	,jo.order_count as orderCount,jo.order_total_amount as orderTotalAmount
                FROM
                	jb_customer ct
                	LEFT JOIN sys_user sub ON ct.business_manager_id = sub.user_id
                	LEFT JOIN sys_user su ON ct.create_by = su.user_id\s
                	LEFT JOIN
                            (SELECT
                                customer_id
                                ,count(id) as order_count,sum(order_total_amount) as order_total_amount
                                FROM
                                jb_order where del_flag=0 and is_process_end='1'
                                GROUP BY customer_id
                            ) jo on ct.id=jo.customer_id
                WHERE
                	ct.del_flag = '0'
                """);
        sql.add(getCustomerSqlWhere(jbCustomerListDto));
        if (StringUtils.isNotBlank(param.getSortKey()) && StringUtils.isNotBlank(param.getSortKeyValues()))
        {
            sql.add(String.format(" order by ct.%s %s", param.getSortKey(), param.getSortKeyValues()));
        } else
        {
            // sql.add(" order by ct.top_up_time desc,ct.id desc");
            sql.add(" order by jo.order_total_amount desc");
        }
        String sqlStr = joSqlUtil.sqlJson(sql.toString(), jbCustomerListDto);
        IPage<JbCustomerListVo> jbCustomerListVoIPage = joSqlUtil.jsonToEntity(baseMapper.pageJson(param.b(), sqlStr), JbCustomerListVo.class);
        jbCustomerListVoIPage.getRecords().forEach(item -> {
            item.setPhoneDesensitized(item);
        });
        return jbCustomerListVoIPage;
    }

    @Override
    public IPage<JbCustomerListVo> appSeniorListData(PageParam param, JbCustomerListDto jbCustomerListDto)
    {
        // 客户和订单，退款，回款，跟进记录 多个表查询数据，且按订单总和排序
        //财务审批完的订单
        StringJoiner sql = new StringJoiner("");
        sql.add("""
                select\s
                ct.id
                ,ct.transfer_customer_time
                ,ct.customer_name AS customerName
                ,ct.customer_status AS customerStatus
                ,ct.customer_star_level AS customerStarLevel
                ,ct.opportunity_source AS opportunitySource
                ,ct.opportunity_channel AS opportunityChannel
                ,ct.business_manager_id AS businessManagerId
                ,ct.latest_followup_time
                ,ct.create_time
                ,ct.update_time
                ,sub.user_name
                ,sub.avatar
                ,jo.order_count,jo.order_total_amount,jo.last_create_time
                ,jr.refund_count,jr.refund_amount
                ,jpr.received_count,jpr.payment_amount
                ,jfr.record_count,jfr.next_followup_time
                ,(select count(DISTINCT product_id) from jb_order jor\s
                	INNER JOIN jb_order_commodity joc on jor.id=joc.order_id
                	where jor.customer_id=ct.id and jor.del_flag=0) as product_count
                ,DATE_ADD(ct.transfer_customer_time, INTERVAL\s
                (select execution_content->>'$.notTrading.day' from jb_rules where rules_code='dept_highseas')\s
                	DAY) as expiration_time
                ,(SELECT
                	IFNULL( DATEDIFF( CURDATE(), ct.latest_followup_time ), 0 )) AS notFollowingDay
                from\s
                jb_customer ct LEFT JOIN sys_user sub on ct.business_manager_id=sub.user_id
                LEFT JOIN\s
                	(SELECT
                	customer_id
                	,count(id) as order_count,sum(order_total_amount) as order_total_amount
                	,MAX(create_time) as last_create_time
                FROM
                	jb_order where del_flag=0 and is_process_end='1'
                	GROUP BY customer_id) jo on ct.id=jo.customer_id
                left JOIN\s
                 (
                	select customer_id\s
                	,count(id) refund_count,SUM(refund_amount) refund_amount
                	from jb_refund  where del_flag=0
                	GROUP BY customer_id
                 ) jr on ct.id=jr.customer_id
                LEFT JOIN\s
                (
                	select customer_id
                	,count(id) received_count,SUM(payment_amount) payment_amount
                	from jb_payment_received where del_flag=0
                	GROUP BY customer_id
                ) jpr on ct.id=jpr.customer_id
                LEFT JOIN
                (
                	select customer_id,count(1) as record_count
                	,MIN(CASE WHEN followup_time > NOW() THEN followup_time END) AS next_followup_time
                	from jb_followup_record where del_flag=0 and data_type=0\s
                	GROUP BY customer_id
                ) jfr on ct.id=jfr.customer_id
                where ct.del_flag=0
                """);
        sql.add(getCustomerSqlWhere(jbCustomerListDto));
        String sqlStr = joSqlUtil.sqlJson(sql.toString(), jbCustomerListDto);
        sql = new StringJoiner("");
        sql.add("select t.* from (")
                .add(sqlStr)
                .add(String.format(") t order by t.%s %s", param.getSortKey(), param.getSortKeyValues()));
        IPage<JbCustomerListVo> jbCustomerListVoIPage = joSqlUtil.jsonToEntity(baseMapper.pageJson(param.b(), sql.toString()), JbCustomerListVo.class);
        jbCustomerListVoIPage.getRecords().forEach(item -> {
            item.setPhoneDesensitized(item);
        });
        return jbCustomerListVoIPage;
    }

    /**
     * app和管理端客户的查询都使用一样的条件
     *
     * @param jbCustomerListDto
     * @return
     */
    private String getCustomerSqlWhere(JbCustomerListDto jbCustomerListDto)
    {
        StringJoiner sql = new StringJoiner("");
        sql.add(joSqlUtil.sqlIf("and ct.customer_status='#{customerStatus}'", jbCustomerListDto.getCustomerStatus()));
        sql.add(joSqlUtil.sqlIf("and ct.customer_type='#{customerType}'", jbCustomerListDto.getCustomerType()));
        sql.add(joSqlUtil.sqlIf("and ct.customer_star_level='#{customerStarLevel}'",
                jbCustomerListDto.getCustomerStarLevel()));

        //TODO 2025年2月18日16:24:06 添加业务经理，因上级引用关联别名混用 sub su
        sql.add(joSqlUtil.sqlIf("""
                        and (
                        INSTR(ct.customer_name,'#{keyWords}')>0
                        or INSTR(ct.phone_number,'#{keyWords}')>0
                        or INSTR(sub.nick_name,'#{keyWords}')>0
                        )
                        """, jbCustomerListDto.getKeyWords()));
        sql.add(joSqlUtil.sqlIf("and ct.latest_followup_time>='#{startTime}'", jbCustomerListDto.getStartTime()));
        sql.add(joSqlUtil.sqlIf("and ct.latest_followup_time<='#{endTime}'", jbCustomerListDto.getEndTime()));
        sql.add(joSqlUtil.sqlIf("and ct.is_invalid<='#{isInvalid}'", jbCustomerListDto.getIsInvalid()));
        sql.add(joSqlUtil.sqlIf("and ct.data_type='#{dataType}'", jbCustomerListDto.getDataType()));
        sql.add(joSqlUtil.sqlIf("and ct.customer_labels='#{customerLabels}'", jbCustomerListDto.getCustomerLabels()));
        sql.add(joSqlUtil.sqlIf("and ct.opportunity_channel='#{opportunityChannel}'", jbCustomerListDto.getOpportunityChannel()));
        sql.add(joSqlUtil.sqlIf("and ct.opportunity_source='#{opportunitySource}'", jbCustomerListDto.getOpportunitySource()));
        LoginUser loginUser = getLoginUser();
        if (ObjectUtils.isNotEmpty(jbCustomerListDto.getCustomerRoleType()))
        {
            switch (jbCustomerListDto.getCustomerRoleType())
            {
                case 1:
                    // 我的客户
                    jbCustomerListDto.setBusinessManagerId(loginUser.getUserId());
                    sql.add(joSqlUtil.sqlIf(" and ct.business_manager_id='#{businessManagerId}'",
                            jbCustomerListDto.getBusinessManagerId()));
                    break;
                case 2:
                    // 下属客户 一个部门的人员，排序自己的
                    jbCustomerListDto.setBusinessManagerId(loginUser.getUserId());
                    jbCustomerListDto.setDeptId(loginUser.getDeptId());
                    sql.add(joSqlUtil.sqlIf(" and sub.dept_id='#{deptId}' ", jbCustomerListDto.getDeptId()));
                    sql.add(joSqlUtil.sqlIf(" and ct.business_manager_id!='#{businessManagerId}' ",
                            jbCustomerListDto.getBusinessManagerId()));
                    break;
                case 3:
                    // 重点客户
                    sql.add(" and ct.id in (select DISTINCT related_id from jb_favorite_table where type=2 and " +
                            "del_flag=0) ");
                    break;
                case 4:
                    // 今日新增
                    LocalDateTime localDateTime = LocalDateTime.now().withHour(0).withMinute(0).withSecond(0).withNano(0);
                    DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
                    String format = localDateTime.format(formatter);
                    sql.add(" and ct.create_time>='" + format + "'");
                    break;
                default:
            }
        }
        // 下次跟进时间
        if (StringUtils.isNotBlank(jbCustomerListDto.getFollowUpStartTime()) && StringUtils.isNotBlank(jbCustomerListDto.getFollowUpEndTime()))
        {

            sql.add(" and ct.id in (select DISTINCT customer_id from jb_followup_record " +
                    "where del_flag=0 and data_type=0 and followup_time>='" + DateUtils.parseDateToStr(DateUtils.YYYY_MM_DD_HH_MM_SS, new Date()) + "' " +
                    "and followup_time>='#{followUpStartTime}' " +
                    "and followup_time<='#{followUpEndTime}')");
        }
        // 最近消费
        if (ObjectUtils.isNotEmpty(jbCustomerListDto.getRecentlyConsumption()))
        {
            switch (jbCustomerListDto.getRecentlyConsumption())
            {
                case 1:
                    // 一周内
                    LocalDateTime[] oneWeekRange = DateUtils.getWeekRange(LocalDateTime.now(), 1);
                    LocalDateTime sTime = oneWeekRange[0];
                    LocalDateTime eTime = oneWeekRange[1];
                    DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
                    String sFormat = sTime.format(formatter);
                    String eFormat = eTime.format(formatter);
                    sql.add(" and ct.id in (select DISTINCT customer_id from jb_followup_record where del_flag=0 and data_type=0 and create_time>='" + sFormat + "' and create_time<='" + eFormat + "')");
                    break;
                case 2:
                    // 2周内
                    LocalDateTime[] oneWeekRange2 = DateUtils.getWeekRange(LocalDateTime.now(), 2);
                    LocalDateTime sTime2 = oneWeekRange2[0];
                    LocalDateTime eTime2 = oneWeekRange2[1];
                    DateTimeFormatter formatter2 = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
                    String sFormat2 = sTime2.format(formatter2);
                    String eFormat2 = eTime2.format(formatter2);
                    sql.add(" and ct.id in (select DISTINCT customer_id from jb_followup_record where del_flag=0 and data_type=0 and create_time>='" + sFormat2 + "' and create_time<='" + eFormat2 + "')");
                    break;
                case 3:
                    // 一月内
                    LocalDateTime[] oneWeekRange3 = DateUtils.getMonthRange(LocalDateTime.now(), 2);
                    LocalDateTime sTime3 = oneWeekRange3[0];
                    LocalDateTime eTime3 = oneWeekRange3[1];
                    DateTimeFormatter formatter3 = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
                    String sFormat3 = sTime3.format(formatter3);
                    String eFormat3 = eTime3.format(formatter3);
                    sql.add(" and ct.id in (select DISTINCT customer_id from jb_followup_record where del_flag=0 and data_type=0 and create_time>='" + sFormat3 + "' and create_time<='" + eFormat3 + "')");
                    break;
                default:
            }
        }
        // 最近消费次数
        if (ObjectUtils.isNotEmpty(jbCustomerListDto.getRecentlyConsumptionNumber()))
        {
            switch (jbCustomerListDto.getRecentlyConsumptionNumber())
            {
                case 1:
                case 2:
                case 3:
                case 4:
                case 5:
                    // 1到5次
                    sql.add(" and ct.id in (select t.customer_id from (");
                    sql.add(" select  customer_id ,COUNT(1) as hCount from jb_order where del_flag=0 GROUP BY customer_id HAVING hCount=" + jbCustomerListDto.getRecentlyConsumptionNumber() + ") t)");
                    break;
                case 6:
                                       // 5次以上
                    sql.add(" and ct.id in (select t.customer_id from (");
                    sql.add(" select  customer_id ,COUNT(1) as hCount from jb_order where del_flag=0 GROUP BY customer_id HAVING hCount>5) t)");
                    break;
                default:
            }
        }
        // 以下条件是后来高级筛选，设置字段的内容
        // 首字母
        sql.add(joSqlUtil.sqlIf(" and CONVERT(SUBSTRING(ct.customer_name_pinyin, 1, 1) USING gbk)='#{initialName}' "
                , jbCustomerListDto.getInitialName()));
        // 地区
        sql.add(joSqlUtil.sqlIf(" and ct.local_area='#{localArea}' "
                , jbCustomerListDto.getLocalArea()));
        // 前归属人
        sql.add(joSqlUtil.sqlIf(" and ct.front_business_manager_id='#{frontBusinessManagerId}' "
                , jbCustomerListDto.getFrontBusinessManagerId()));
        // 保护到期时间
        if (StringUtils.isNotBlank(jbCustomerListDto.getProtectTime()))
        {
            String[] split = jbCustomerListDto.getProtectTime().split(",");
            if (ObjectUtils.isNotEmpty(split) && split.length == 2)
            {
                // 获取保护的天数
                JbRules one = jbRulesService.getOne(Wrappers.lambdaQuery(JbRules.class).eq(JbRules::getRulesCode, Constants.DEPT_HIGHSEAS));
                JbDeptHighseasRulesJson bean = BeanUtil.toBean(one.getExecutionContent(), JbDeptHighseasRulesJson.class);
                Integer day = bean.getNotTrading().getDay();
                if (ObjectUtils.isNotEmpty(day))
                {
                    sql.add(String.format(" and DATE_ADD(ct.transfer_customer_time, INTERVAL %s DAY)>='%s' " +
                            "and DATE_ADD(ct.transfer_customer_time, INTERVAL 10 DAY)<='%s'", day, split[0], split[1]));
                }
            }
        }
        // 实际跟进时间,,提的问题没有回答，暂时先不做

        // 下次跟进时间
        if (StringUtils.isNotBlank(jbCustomerListDto.getFollowUpTime()))
        {
            String[] split = jbCustomerListDto.getFollowUpTime().split(",");
            if (ObjectUtils.isNotEmpty(split) && split.length == 2)
            {
                sql.add(String.format(" and ct.id in (select DISTINCT customer_id from jb_followup_record where del_flag=0" +
                                " and data_type=0 and followup_time>='%s' and create_time>='%s' and create_time<='%s')"
                        , DateUtils.parseDateToStr(DateUtils.YYYY_MM_DD_HH_MM_SS, new Date()), split[0], split[1]));
            }
        }
        // 创建时间
        if (StringUtils.isNotBlank(jbCustomerListDto.getCreateTimes()))
        {
            String[] split = jbCustomerListDto.getCreateTimes().split(",");
            if (ObjectUtils.isNotEmpty(split) && split.length == 2)
            {
                sql.add(String.format(" and ct.create_time>='%s' and ct.create_time<='%s' "
                        , split[0], split[1]));
            }
        }
        // 创建人员
        sql.add(joSqlUtil.sqlIf(" and ct.create_by='#{createBy}' "
                , jbCustomerListDto.getCreateBy()));
        // 所属部门
        if (ObjectUtils.isNotEmpty(jbCustomerListDto.getCurrentDeptId()))
        {
            sql.add(String.format(" and ct.business_manager_id in (select user_id from sys_user where del_flag=0 and dept_id=%s)"
                    , jbCustomerListDto.getCurrentDeptId()));
        }
        // 前所属部门
        if (ObjectUtils.isNotEmpty(jbCustomerListDto.getFrontDeptId()))
        {
            sql.add(String.format(" and ct.front_business_manager_id in (select user_id from sys_user where del_flag=0 and dept_id=%s)"
                    , jbCustomerListDto.getFrontDeptId()));
        }
        // 更新时间
        if (StringUtils.isNotBlank(jbCustomerListDto.getUpdateTimes()))
        {
            String[] split = jbCustomerListDto.getUpdateTimes().split(",");
            if (ObjectUtils.isNotEmpty(split) && split.length == 2)
            {
                sql.add(String.format(" and ct.update_time>='%s' and ct.update_time<='%s' "
                        , split[0], split[1]));
            }
        }
        getRoleData(sql);
        return sql.toString();
    }
    private void getRoleData(StringJoiner sql)
    {
        //角色数据权限
        String roleData=sysDataScopeFactoryService.fnStrDataScope(Constants.PUBLIC_NUMBER_0.toString());
        if (StrUtil.isNotBlank(roleData))
        {
            sql.add(String.format(" and ct.business_manager_id in (%s)", roleData));
        }
    }


    @Override
    public IPage<JbCustomerListVo> favoriteSeniorListData(IPage iPage, JbCustomerListDto jbCustomerListDto)
    {
        StringJoiner sql = new StringJoiner(" ").add("""
                select
                ct.id,
                ct.customer_name as customerName,
                ct.customer_status as customerStatus,
                ct.customer_star_level as customerStarLevel,
                ct.opportunity_source as opportunitySource,
                su.user_name as createByName,
                sub.user_name as businessManagerName,
                ct.phone_number as phoneNumber,
                ct.latest_followup_time as latestFollowupTime,
                (SELECT IFNULL(DATEDIFF(CURDATE(), ct.latest_followup_time), 0)) AS notFollowingDay
                 from jb_customer ct LEFT JOIN sys_user sub on ct.business_manager_id=sub.user_id
                 LEFT JOIN sys_user su on ct.create_by=su.user_id
                  INNER JOIN jb_favorite_table ft on ft.related_id=ct.id
                where ct.del_flag='0' and ft.del_flag='0' and ft.type=2  \s
                              
                """);

        sql.add(joSqlUtil.sqlIf("and ct.business_manager_id='#{businessManagerId}'",
                jbCustomerListDto.getBusinessManagerId()));
        sql.add(joSqlUtil.sqlIf("and ct.customer_status='#{customerStatus}'", jbCustomerListDto.getCustomerStatus()));
        sql.add(joSqlUtil.sqlIf("and ct.customer_type='#{customerType}'", jbCustomerListDto.getCustomerType()));
        sql.add(joSqlUtil.sqlIf("and ct.customer_star_level='#{customerStarLevel}'",
                jbCustomerListDto.getCustomerStarLevel()));
        sql.add(joSqlUtil.sqlIf("and (INSTR(ct.customer_name,'#{keyWords}')>0 or INSTR(ct.phone_number,'#{keyWords}')" +
                ">0 )", jbCustomerListDto.getKeyWords()));
        sql.add(joSqlUtil.sqlIf("and ct.latest_followup_time>='#{startTime}'", jbCustomerListDto.getStartTime()));
        sql.add(joSqlUtil.sqlIf("and ct.latest_followup_time<='#{endTime}'", jbCustomerListDto.getEndTime()));
        sql.add(joSqlUtil.sqlIf("and ct.is_invalid<='#{isInvalid}'", jbCustomerListDto.getIsInvalid()));
        sql.add(joSqlUtil.sqlIf("and ct.data_type='#{dataType}'", jbCustomerListDto.getDataType()));
        sql.add(joSqlUtil.sqlIf("and ct.customer_labels='#{customerLabels}'", jbCustomerListDto.getCustomerLabels()));
        sql.add(joSqlUtil.sqlIf("and ft.user_id='#{createBy}'", jbCustomerListDto.getCreateBy()));
        getRoleData(sql);
        sql.add(" order by ct.top_up desc,ct.id desc");
        String sqlStr = joSqlUtil.sqlJson(sql.toString(), jbCustomerListDto);

        return joSqlUtil.jsonToEntity(baseMapper.pageJson(iPage, sqlStr), JbCustomerListVo.class);
    }

    @Override
    public IPage<CustomerDynamicListVo> customerDynamicList(IPage iPage, JbCustomerListDto jbCustomerListDto)
    {
        JbCustomer byId = this.getById(jbCustomerListDto.getId());
        IPage<JbBusinessOperRecord> page = jbBusinessOperRecordService.page(iPage, Wrappers.lambdaQuery(JbBusinessOperRecord.class)
                .eq(JbBusinessOperRecord::getModuleCode, BusinessOperModule.CUSTOMER_DYNAMIC.getCode())
                .eq(JbBusinessOperRecord::getRecordId, jbCustomerListDto.getId())
                .eq((ObjectUtils.isNotEmpty(jbCustomerListDto.getIsFollowUp())
                                && Constants.PUBLIC_NUMBER_0.equals(jbCustomerListDto.getIsFollowUp()))
                        , JbBusinessOperRecord::getSubModuleCode, BusinessOperModule.CUSTOMER_FOLLOWUP.getCode())
                .orderByDesc(JbBusinessOperRecord::getId));
        List<CustomerDynamicListVo> voList = Lists.newArrayList();
        if (ObjectUtils.isNotEmpty(page.getRecords()))
        {
            List<Long> userIds = page.getRecords().stream().filter(a -> ObjectUtils.isNotEmpty(a.getBusinessId())).map(JbBusinessOperRecord::getBusinessId).collect(Collectors.toList());
            Map<Long, SysUser> collect = Maps.newHashMap();
            if (ObjectUtils.isNotEmpty(userIds))
            {
                List<SysUser> list = sysUserService.list(Wrappers.lambdaQuery(SysUser.class).in(SysUser::getUserId, userIds)
                        .select(SysUser::getUserId, SysUser::getUserName));
                if (ObjectUtils.isNotEmpty(list))
                {
                    collect = list.stream().collect(Collectors.toMap(SysUser::getUserId, Function.identity()));
                }
            }
            // 获取评论
            String recordIds = page.getRecords().stream().filter(a -> BusinessOperModule.CUSTOMER_FOLLOWUP.getCode()
                    .equals(a.getSubModuleCode())).map(a -> a.getOtherRecordId().toString()).collect(Collectors.joining(","));
            Map<Long, List<JbFollowupEvaluationVo>> commMap = Maps.newHashMap();
            if (StringUtils.isNotBlank(recordIds))
            {
                StringJoiner joiner = new StringJoiner(" ")
                        .add("""
                                       select fe.id,fe.record_id,fe.comment_content,fe.create_time,su.user_name as createName from jb_followup_evaluation fe 
                                      left JOIN sys_user su on su.user_id=fe.create_by  where  fe.del_flag='0'
                                """);
                joiner.add(" and fe.record_id in (" + recordIds + ") order by fe.id desc");
                List<JbFollowupEvaluationVo> jbFollowupEvaluationVos =
                        joSqlUtil.jsonToEntity(baseMapper.findJson(joiner.toString()), JbFollowupEvaluationVo.class);
                commMap =
                        jbFollowupEvaluationVos.stream().collect(Collectors.groupingBy(JbFollowupEvaluationVo::getRecordId));
            }
            for (JbBusinessOperRecord a : page.getRecords())
            {
                CustomerDynamicListVo vo = new CustomerDynamicListVo();
                BeanUtils.copyProperties(a, vo);
                vo.setCustomerName(byId.getCustomerName());
                SysUser sysUser = collect.get(a.getBusinessId());
                if (ObjectUtils.isNotEmpty(sysUser))
                {
                    vo.setBusinessName(sysUser.getUserName());
                    vo.setAvatar(sysUser.getAvatar());
                }
                List<JbFollowupEvaluationVo> jbFollowupEvaluationVos1 = commMap.get(a.getOtherRecordId());
                vo.setCommentList(jbFollowupEvaluationVos1);
                vo.setCommentNumber(ObjectUtils.isNotEmpty(jbFollowupEvaluationVos1) ?
                        jbFollowupEvaluationVos1.size() : Constants.PUBLIC_NUMBER_0);
                voList.add(vo);
            }
        }
        IPage<CustomerDynamicListVo> pageVo = new Page<>();
        BeanUtils.copyProperties(page, pageVo);
        pageVo.setRecords(voList);
        return pageVo;
    }

    @Override
    public JbCustomerDto detailsInfo(Long id)
    {
        JbCustomer byId = this.getById(id);
        byId.setPhoneDesensitized(byId);
        JbCustomerDto detailsVo = new JbCustomerDto();
        BeanUtils.copyProperties(byId, detailsVo);
        // 获取作物结构销售情况
        List<JbCustomerCropStructure> cropStructureList = jbCustomerCropStructureService.list(Wrappers.lambdaQuery(JbCustomerCropStructure.class).eq(JbCustomerCropStructure::getCustomerId, id));
        detailsVo.setCropStructuresList(cropStructureList);
        // 跟进记录查询
        List<JbFollowupRecord> jbFollowupRecords = jbFollowupRecordService.list(Wrappers.lambdaQuery(JbFollowupRecord.class)
                .eq(JbFollowupRecord::getCustomerId, id));
        if (ObjectUtils.isNotEmpty(jbFollowupRecords))
        {
            JbFollowupRecord record = jbFollowupRecords.get(jbFollowupRecords.size() - 1);
            JbFollowupRecordListVo bean = BeanUtil.toBean(record, JbFollowupRecordListVo.class);
            SysUser one = sysUserService.getOne(Wrappers.lambdaQuery(SysUser.class).eq(SysUser::getUserId, byId.getBusinessManagerId())
                    .select(SysUser::getUserName));
            bean.setStaffName(ObjectUtils.isNotEmpty(one)?one.getUserName():StringUtils.EMPTY);
            detailsVo.setFollowupRecords(bean);
        }
        SysUser one = sysUserService.getOne(Wrappers.lambdaQuery(SysUser.class).eq(SysUser::getUserId,            byId.getBusinessManagerId())
                .select(SysUser::getUserName));
        detailsVo.setBusinessManagerName(ObjectUtils.isNotEmpty(one)?one.getUserName():StringUtils.EMPTY);
        return detailsVo;
    }

    @Override
    @Transactional
    public Boolean updateInfoById(JbCustomerUpdateDto jbCustomerUpdateDto)
    {
        JbCustomer byId = getById(jbCustomerUpdateDto.getId());
        if (StringUtils.isNotBlank(jbCustomerUpdateDto.getPhoneNumber())
        && DesensitizedType.PHONE.desensitizer().apply(byId.getPhoneNumber())
                .equals(jbCustomerUpdateDto.getPhoneNumber()))
        {
            //如果带星的不更新手机号
            jbCustomerUpdateDto.setPhoneNumber(null);
        }
        if (StringUtils.isNotBlank(jbCustomerUpdateDto.getPhoneNumber()) &&
                !byId.getPhoneNumber().equals(jbCustomerUpdateDto.getPhoneNumber()))
        {
            // 表示换手机号了，则验证新的手机是否存在
            isPhoneExist(jbCustomerUpdateDto);
        }
        JbCustomer updateInfo = new JbCustomer();
        BeanUtils.copyProperties(jbCustomerUpdateDto, updateInfo);
        if (ObjectUtils.isNotEmpty(jbCustomerUpdateDto.getFollowupRecords()))
        {
            // 更新客户的最后跟进时间
//            updateInfo.setLatestFollowupTime(jbCustomerUpdateDto.getFollowupRecords().getFollowupTime());
        }
        if (!byId.getBusinessManagerId().equals(jbCustomerUpdateDto.getBusinessManagerId()))
        {
            // 不是原来的业务经理，则新增加一个新的客户和用户的关系。
            JbCustomerUser customerUser = new JbCustomerUser();
            customerUser.setCustomerId(jbCustomerUpdateDto.getId());
            customerUser.setUserId(jbCustomerUpdateDto.getBusinessManagerId());
            jbCustomerUserService.save(customerUser);
            updateInfo.setFrontBusinessManagerId(byId.getBusinessManagerId());
            updateInfo.setTransferCustomerTime(new Date());
            setBusinessOperRecord(updateInfo, Constants.PUBLIC_NUMBER_2);
            // 更新业务经理，验证业务经理的客户数量，和客户类型是否到上限
            isCustomerNumber(jbCustomerUpdateDto);
        }
        updateInfo.setCustomerNamePinyin(ChineseCharacterUtil.getUpperCase(updateInfo.getCustomerName(), true));
        this.updateById(updateInfo);
        // 删除指定的作物结构和销售情况


        LambdaQueryWrapper<JbCustomerCropStructure> wrapper = new LambdaQueryWrapper();
        wrapper.eq(JbCustomerCropStructure::getCustomerId, jbCustomerUpdateDto.getId());
//        String customerType = byId.getCustomerType();
//        if(Constants.CUSTOMER_TYPE_1003.equals(customerType))
//        {
//            wrapper.eq(JbCustomerCropStructure::getCropType,Constants.PUBLIC_NUMBER_1);
//            //农户
//        }else if(Constants.CUSTOMER_TYPE_1001.equals(customerType) ||
//                Constants.CUSTOMER_TYPE_1002.equals(customerType))
//        {
//            //零售商，经销商
//            wrapper.eq(JbCustomerCropStructure::getCropType,Constants.PUBLIC_NUMBER_2);
//        }
        jbCustomerCropStructureService.remove(wrapper);
        // 添加作物结构和销售情况
        if (ObjectUtils.isNotEmpty(jbCustomerUpdateDto.getCropStructuresList()))
        {
            List<JbCustomerCropStructure> cropStructuresList = jbCustomerUpdateDto.getCropStructuresList();
            cropStructuresList.forEach(a -> a.setCustomerId(jbCustomerUpdateDto.getId()));
            jbCustomerCropStructureService.saveBatch(cropStructuresList);
        }
        // 添加跟进任务
        if (ObjectUtils.isNotEmpty(jbCustomerUpdateDto.getFollowupRecords()))
        {
            jbCustomerUpdateDto.getFollowupRecords().setCustomerId(updateInfo.getId());
            jbCustomerUpdateDto.getFollowupRecords().setDataType(Constants.PUBLIC_NUMBER_0);
            jbCustomerUpdateDto.getFollowupRecords().setTaskStatus(Constants.JBFOLLOWUPRECORD_TASKSTATUS_1001);
            jbFollowupRecordService.save(jbCustomerUpdateDto.getFollowupRecords());
        }
        return true;
    }

    @Override
    @Transactional
    public Boolean editTopUp(Long id)
    {
        return  this.update(Wrappers.lambdaUpdate(JbCustomer.class).eq(JbCustomer::getId, id)
                .set(JbCustomer::getTopUp, Constants.PUBLIC_NUMBER_0)
                .set(JbCustomer::getTopUpTime, new Date()));
    }

    @Override
    @Transactional
    public Boolean transferCustomer(JbCustomerTransferDto jbCustomerTransferDto)
    {
        List<Long> ids = jbCustomerTransferDto.getIds();
        List<JbCustomer> jbCustomers = this.listByIds(ids);
        Map<Long, Long> collect = jbCustomers.stream().collect(Collectors.toMap(JbCustomer::getId, JbCustomer::getBusinessManagerId));
        List<JbCustomerUser> addBatch = Lists.newArrayList();
        List<JbCustomer> updateBatch = Lists.newArrayList();
        ids.forEach(a ->
        {
            JbCustomerUser customerUser = new JbCustomerUser();
            customerUser.setCustomerId(a);
            customerUser.setUserId(jbCustomerTransferDto.getBusinessManagerId());
            customerUser.setRemark(jbCustomerTransferDto.getRemark());
            customerUser.setFrontUserId(collect.get(a));
            addBatch.add(customerUser);

            JbCustomer jbCustomer = new JbCustomer();
            jbCustomer.setId(a);
            jbCustomer.setBusinessManagerId(jbCustomerTransferDto.getBusinessManagerId());
            jbCustomer.setFrontBusinessManagerId(collect.get(a));
            jbCustomer.setDataType(jbCustomerTransferDto.getDataType());
            jbCustomer.setTransferCustomerTime(new Date());
            updateBatch.add(jbCustomer);
        });

        // 验证是否已经有人操作过、验证客户数据、客户类型数量
        verifyOper(jbCustomerTransferDto, jbCustomers);
        // 插入最新的关系和备注
        jbCustomerUserService.saveBatch(addBatch);
        // 更新客户的业务经理
        this.updateBatchById(updateBatch);
        // 记录动态数据
        setBusinessOperRecordBatch(updateBatch, Constants.PUBLIC_NUMBER_2);
        return true;
    }

    /**
     * 验证是否数据是否变更过
     *
     * @param jbCustomerTransferDto
     */
    private void verifyOper(JbCustomerTransferDto jbCustomerTransferDto, List<JbCustomer> jbCustomers)
    {
        JbRules jbRules = jbRulesService.getOne(Wrappers.lambdaQuery(JbRules.class).eq(JbRules::getRulesCode, Constants.DEPT_HIGHSEAS_ALLOCATION));
        // 操作类型来源 0=我的客户1=无效客户2=部门公司3=公司公海 用于service区分操作来源
        // 处理部门公海数据和，无效客户，因领取操作后类型变更别人不能操作
        List<Long> ids = jbCustomerTransferDto.getIds();
        switch (jbCustomerTransferDto.getOpType())
        {
            case 1:
//                List<JbCustomer> collect = jbCustomers.stream().filter(a -> a.getDataType().equals(Constants.PUBLIC_NUMBER_0)
//                        && a.getIsInvalid().equals(Constants.PUBLIC_NUMBER_1)).collect(Collectors.toList());
//                if (ObjectUtils.isEmpty(collect) || ids.size() != collect.size())
//                {
//                    throw new ServiceException(BusinessErrorEnum.CUSTOMER_TRANSFER_20003);
//                }
                // 验证系统规则，前负责人在N天内不能领取
                verifyRule(jbRules, jbCustomerTransferDto, jbCustomers);
                break;
            case 2:
//                List<JbCustomer> collectDept = jbCustomers.stream().filter(a -> a.getDataType().equals(Constants.PUBLIC_NUMBER_2)
//                ).collect(Collectors.toList());
//                if (ObjectUtils.isEmpty(collectDept) || ids.size() != collectDept.size())
//                {
//                    throw new ServiceException(BusinessErrorEnum.CUSTOMER_TRANSFER_20003);
//                }
                break;
            case 3:
                // 验证系统规则，前负责人在N天内不能领取
                verifyRule(jbRules, jbCustomerTransferDto, jbCustomers);
                break;
            default:
        }
        // 过滤掉以前是自己的客户，可能操作自己的客户在转移给自己。
        List<JbCustomer> collect = jbCustomers.stream().filter(a -> !a.getBusinessManagerId().equals(jbCustomerTransferDto.getBusinessManagerId())).collect(Collectors.toList());
        if (ObjectUtils.isNotEmpty(collect))
        {
            // 不等于null是操作别的客户到自己名下
            // 等于null，不用处理，因自己操作到自己名字，客户数量和客户类型数据不变
            // 验证规则客户数上限，客户类型分别设置客户数上限
            verifyCustomerNumber(jbRules, jbCustomerTransferDto.getBusinessManagerId(), collect);
        }
    }

    /**
     * 验证规则客户数上限，客户类型分别设置客户数上限
     *
     * @return
     */
    private void verifyCustomerNumber(JbRules one, Long businessManagerId, List<JbCustomer> jbCustomerList)
    {
        JbdeptHighseasAllocationRulesJson bean = BeanUtil.toBean(one.getExecutionContent(), JbdeptHighseasAllocationRulesJson.class);
        if (bean.getUserCustomerTopLineFlag() || bean.getCustomerTypeTopLineFlag())
        {
            StringJoiner sql = new StringJoiner(" ").add("""
                    SELECT
                    	jc.id,
                    	jc.customer_type,
                    	( SELECT count( 1 ) FROM jb_order WHERE del_flag = 0 AND customer_id = jc.id ) AS dataType\s
                    FROM
                    	jb_customer jc\s
                    WHERE
                    	jc.del_flag = 0\s
                                  
                    """);
            sql.add(String.format(" AND jc.business_manager_id = %s", businessManagerId));
            List<JbCustomer> jbCustomers = joSqlUtil.jsonToEntity(baseMapper.findJson(sql.toString()),
                    JbCustomer.class);
            if (ObjectUtils.isEmpty(jbCustomers))
            {
                return;
            }
            int businessCustomerNumber = 0;
            // 客户数量处理
            if (bean.getUserCustomerTopLineFlag())
            {
                // 按员工设置不同的客户数上限
                if (bean.getCustomerNumberFlag() && bean.getCustomerNotTradingFlag())
                {
                    // 此规则仅限制“未成交”客户 ，用DataType代替订单数量字段
                    businessCustomerNumber = jbCustomers.stream().filter(a -> a.getDataType() > 0).collect(Collectors.toList()).size();
                } else
                {
                    businessCustomerNumber = jbCustomers.size();
                }
                // 比较设置规则的客户最大数量
                if (businessCustomerNumber > 0)
                {
                    int ruleNumber = 0;
                    // 匹配有没有设置单独员工的数量
                    List<JbCustomerNumberContentJson> userCustomerList = bean.getUserCustomerList();
                    for (JbCustomerNumberContentJson contentJson : userCustomerList)
                    {
                        // 默认null是使用全部员工，
                        Long[] userIds = contentJson.getUserIds();
                        if (ObjectUtils.isEmpty(userIds))
                        {
                            ruleNumber = contentJson.getCustomerNumber();
                        } else
                        {
                            boolean present = Arrays.stream(userIds).filter(a -> a.equals(businessManagerId)).findAny().isPresent();
                            if (present)
                            {
                                ruleNumber = contentJson.getCustomerNumber();
                                break;
                            }
                        }
                    }
                    // 转移客户 加个将要操作的数据条数
                    businessCustomerNumber = businessCustomerNumber + jbCustomerList.size();
                    if (businessCustomerNumber > ruleNumber)
                    {
                        throw new ServiceException(BusinessErrorEnum.CUSTOMER_TRANSFER_20005);
                    }
                }
            }
            // 客户类型数据处理
            if (bean.getCustomerTypeTopLineFlag())
            {
                // 根据客户类型分别设置客户数上限
                Map<String, Long> collect = jbCustomers.stream().collect(Collectors.groupingBy(JbCustomer::getCustomerType, Collectors.counting()));
                if (ObjectUtils.isNotEmpty(collect))
                {
                    Map<String, Long> collectByFront = jbCustomerList.stream().collect(Collectors.groupingBy(JbCustomer::getCustomerType, Collectors.counting()));
                    for (Map.Entry<String, Long> entry : collectByFront.entrySet())
                    {
                        String key = entry.getKey();
                        Long value = entry.getValue();
                        int keyValues = ObjectUtils.isEmpty(collect.get(key)) ? 0 : collect.get(key).intValue();
                        // 转移客户 加个将要操作客户类型数量
                        int compareNumber = keyValues + value.intValue();
                        if (Constants.CUSTOMER_TYPE_1003.equals(key) && compareNumber > bean.getPeasantNumber())
                        {
                            // 获取的农户数量大于设置的农户数量
                            throw new ServiceException(BusinessErrorEnum.CUSTOMER_TRANSFER_20006);
                        }
                        if (Constants.CUSTOMER_TYPE_1002.equals(key) && compareNumber > bean.getTradesmanNumber())
                        {
                            // 获取的农户数量大于设置的农户数量
                            throw new ServiceException(BusinessErrorEnum.CUSTOMER_TRANSFER_20007);
                        }
                        if (Constants.CUSTOMER_TYPE_1001.equals(key) && compareNumber > bean.getDealerNumber())
                        {
                            // 获取的农户数量大于设置的农户数量
                            throw new ServiceException(BusinessErrorEnum.CUSTOMER_TRANSFER_20008);
                        }
                    }
                }
            }
        }
    }

    /**
     * 验证系统规则，前负责人在N天内不能领取
     *
     * @return
     */
    private boolean verifyRule(JbRules one, JbCustomerTransferDto jbCustomerTransferDto, List<JbCustomer> jbCustomers)
    {
        JbdeptHighseasAllocationRulesJson bean = BeanUtil.toBean(one.getExecutionContent(), JbdeptHighseasAllocationRulesJson.class);
        if (bean.getCustomerAllocationFlag() && bean.getCustomerAllocationDay() > Constants.PUBLIC_NUMBER_0)
        {
            Map<Long, JbCustomer> collect = jbCustomers.stream().collect(Collectors.toMap(JbCustomer::getId, Function.identity()));
            // 同时操作多个人有一个不满足，则返回一次
            for (Long a : jbCustomerTransferDto.getIds())
            {
                // 客户被转移或者系统定时划入公海后，前负责人在N天内不能领取。
                JbCustomer fromBusines = collect.get(a);
                if (jbCustomerTransferDto.getBusinessManagerId().equals(fromBusines.getBusinessManagerId()))
                {
                    // 是一个人，
                    Date dataTypeTime = fromBusines.getDataTypeTime();
                    Date now = new Date();
                    int i = DateUtils.differentDaysByMillisecond(dataTypeTime, now);
                    if (i < bean.getCustomerAllocationDay())
                    {
                        throw new ServiceException(BusinessErrorEnum.CUSTOMER_TRANSFER_20003);
                    }
                }
            }
        }
        return false;
    }

    @Override
    public Boolean transferHighSeas(JbCustomerTransferDto jbCustomerTransferDto)
    {
        JbCustomer jbCustomer = new JbCustomer();
        jbCustomer.setDataType(jbCustomerTransferDto.getDataType());
        jbCustomer.setDataTypeTime(jbCustomerTransferDto.getDataTypeTime());
        return this.update(jbCustomer, Wrappers.lambdaQuery(JbCustomer.class).in(JbCustomer::getId, jbCustomerTransferDto.getIds()));
    }

    @Override
    public JbCustomerOverViewVo overViewInfo(Long id)
    {
        JbCustomer byId = this.getById(id);
        byId.setPhoneDesensitized(byId);
        JbCustomerOverViewVo vo = new JbCustomerOverViewVo();
        BeanUtils.copyProperties(byId, vo);
        SysUser one = sysUserService.getOne(Wrappers.lambdaQuery(SysUser.class).eq(SysUser::getUserId, byId.getBusinessManagerId())
                .select(SysUser::getUserName));
        vo.setBusinessManagerName(Optional.ofNullable(one).map(a -> a.getUserName()).orElse(null));
        long count = jbFollowupRecordService.count(Wrappers.lambdaQuery(JbFollowupRecord.class)
                .eq(JbFollowupRecord::getDataType, Constants.PUBLIC_NUMBER_1)
                .eq(JbFollowupRecord::getCustomerId, id));
        vo.setFollowUpRecordNumber(count);
        long belongToNumber = jbCustomerUserService.count(Wrappers.lambdaQuery(JbCustomerUser.class).eq(JbCustomerUser::getCustomerId, id));
        vo.setBelongToNumber(belongToNumber);
        List<JbFollowupRecord> jbFollowupRecords = jbFollowupRecordService.list(Wrappers.lambdaQuery(JbFollowupRecord.class)
                .eq(JbFollowupRecord::getCustomerId, id)
                .eq(JbFollowupRecord::getDataType, Constants.PUBLIC_NUMBER_0)
                .ge(JbFollowupRecord::getFollowupTime, new Date()));
        if (ObjectUtils.isNotEmpty(jbFollowupRecords))
        {
            vo.setNextFollowUpTime(jbFollowupRecords.get(0).getFollowupTime());
        }
        long orderCount = jbOrderService.count(Wrappers.lambdaQuery(JbOrder.class).eq(JbOrder::getCustomerId, id));
        vo.setOrderRecordNumber(orderCount);
        long opeLogNumber = jbBusinessOperRecordService.count(Wrappers.lambdaQuery(JbBusinessOperRecord.class)
                .eq(JbBusinessOperRecord::getModuleCode, BusinessOperModule.CUSTOMER_OPER.getCode())
                .eq(JbBusinessOperRecord::getRecordId, id));
        vo.setOpeLogNumber(opeLogNumber);
        // 区域名称
        if (StringUtils.isNotBlank(byId.getLocalArea()))
        {
            DivisionsCode code = new DivisionsCode();
            code.setCode(byId.getLocalArea());
            List<DivisionsCodeAllVo> allByCode = divisionsCodeService.findAllByCode(code);
            if (ObjectUtils.isNotEmpty(allByCode))
            {
                DivisionsCodeAllVo divisionsCodeAllVo = allByCode.get(0);
                vo.setLocalArea(divisionsCodeAllVo.getProvincesName() + divisionsCodeAllVo.getCitiesName() + divisionsCodeAllVo.getAreasName() + divisionsCodeAllVo.getStreetsName());
            }
        }
        // 获取锁定时间
        if (StringUtils.isNotBlank(vo.getBusinessManagerName()))
        {
            JbRules rulesOne = jbRulesService.getOne(Wrappers.lambdaQuery(JbRules.class).eq(JbRules::getRulesCode, Constants.DEPT_HIGHSEAS));
            JbDeptHighseasRulesJson bean = BeanUtil.toBean(rulesOne.getExecutionContent(), JbDeptHighseasRulesJson.class);
            Integer day = bean.getNotTrading().getDay();
            Date transferCustomerTime = byId.getTransferCustomerTime();
            if (ObjectUtils.isNotEmpty(day) && ObjectUtils.isNotEmpty(transferCustomerTime))
            {
                Date date = DateUtils.dateAddDay(transferCustomerTime, day);
                String s = DateUtils.parseDateToStr(DateUtils.YYYY_MM_DD, date);
                vo.setBusinessManagerName(String.format("%s (已锁定，保护到期时间%s)", vo.getBusinessManagerName(), s));
            }
        }
        // 获取最新的作物结构
        vo.setCropStructures(cropStructureList(id));
        return vo;
    }

    /**
     * 获取作物和销售情况，且作物和产品转名称
     * @param id
     * @return
     */
    private List<JbCustomerCropStructure> cropStructureList(Long id)
    {
        int year = LocalDateTime.now().getYear();
        List<JbCustomerCropStructure> customerCropStructureList = jbCustomerCropStructureService.list(Wrappers.lambdaQuery(JbCustomerCropStructure.class)
                .eq(JbCustomerCropStructure::getCustomerId, id)
                .le(JbCustomerCropStructure::getCropYear, year)
                .orderByDesc(JbCustomerCropStructure::getCropYear));
        if (ObjectUtils.isNotEmpty(customerCropStructureList))
        {
            // 获取最近一年的数据
            JbCustomerCropStructure jbCustomerCropStructure = customerCropStructureList.get(0);
            // 获取list离当前年最近一年的数据
            customerCropStructureList = customerCropStructureList.stream().filter(a ->
                    a.getCropYear().equals(jbCustomerCropStructure.getCropYear())).collect(Collectors.toList());

            // 匹配作物名称和产品名称
            for (JbCustomerCropStructure item : customerCropStructureList)
            {
                if (StringUtils.isNotBlank(item.getCropVariety())
                        && Constants.PUBLIC_NUMBER_1.intValue()==item.getCropType().intValue())
                {
                    // 作物
                    List<Long> cropLists = Arrays.stream(item.getCropVariety().split(","))
                            .map(Long::valueOf).collect(Collectors.toList());
                    List<JbCropVariety> jbCropGrowthPeriods = jbCropVarietyService.listByIds(cropLists);
                    if (ObjectUtils.isNotEmpty(jbCropGrowthPeriods))
                    {
                        String collect = jbCropGrowthPeriods.stream().map(JbCropVariety::getCropName)
                                .collect(Collectors.joining(","));
                        item.setCropVariety(collect);
                    }
                }else if (StringUtils.isNotBlank(item.getMainProducts())
                        && Constants.PUBLIC_NUMBER_2.intValue()==item.getCropType().intValue())
                {
                    // 产品
                    List<Long> cropLists = Arrays.stream(item.getMainProducts().split(","))
                            .map(Long::valueOf).collect(Collectors.toList());
                    List<JbProduct> jbCropGrowthPeriods = jbProductService.listByIds(cropLists);
                    if (ObjectUtils.isNotEmpty(jbCropGrowthPeriods))
                    {
                        String collect = jbCropGrowthPeriods.stream().map(JbProduct::getProductName)
                                .collect(Collectors.joining(","));
                        item.setMainProducts(collect);
                    }
                }
            }
        }
        return customerCropStructureList;
    }

    @Override
    public JbCustomerDetailedInforMtionVo detailedInforMtion(Long id)
    {
        JbCustomer byId = this.getById(id);
        byId.setPhoneDesensitized(byId);
        JbCustomerDetailedInforMtionVo vo = new JbCustomerDetailedInforMtionVo();
        BeanUtils.copyProperties(byId, vo);
        // 处理先业务经理，前业务经理，创建，和部门数据
        List<Long> userIds = Lists.newArrayList();
        userIds.add(byId.getFrontBusinessManagerId());
        userIds.add(byId.getBusinessManagerId());
        userIds.add(byId.getCreateBy());
        List<SysUser> userList = sysUserService.list(Wrappers.lambdaQuery(SysUser.class).in(SysUser::getUserId, userIds)
                .select(SysUser::getUserId, SysUser::getUserName, SysUser::getDeptId));
        if (ObjectUtils.isNotEmpty(userList))
        {
            Map<Long, SysUser> userMap = userList.stream().collect(Collectors.toMap(SysUser::getUserId, Function.identity()));
            Map<Long, String> detpMap = Maps.newHashMap();
            List<Long> collect = userList.stream().map(a -> a.getDeptId()).collect(Collectors.toList());
            List<SysDept> sysDeptList = sysDeptService.list(Wrappers.lambdaQuery(SysDept.class).in(SysDept::getDeptId, collect)
                    .select(SysDept::getDeptId, SysDept::getDeptName));
            if (ObjectUtils.isNotEmpty(sysDeptList))
            {
                detpMap = sysDeptList.stream().collect(Collectors.toMap(SysDept::getDeptId, SysDept::getDeptName));
            }
            SysUser sysUser = new SysUser();
            if (ObjectUtils.isNotEmpty(userMap.get(byId.getBusinessManagerId())))
            {
                sysUser = userMap.get(byId.getBusinessManagerId());
            }
            vo.setBusinessManagerName(sysUser.getUserName());
            vo.setDeptName(detpMap.get(sysUser.getDeptId()));
            if (ObjectUtils.isNotEmpty(byId.getFrontBusinessManagerId()))
            {
                if (ObjectUtils.isNotEmpty(userMap.get(byId.getFrontBusinessManagerId())))
                {
                    sysUser = userMap.get(byId.getFrontBusinessManagerId());
                    vo.setFrontBusinessManagerName(sysUser.getUserName());
                    vo.setFrontDeptName(detpMap.get(sysUser));
                }
            }

            vo.setCreateByName(ObjectUtils.isNotEmpty(userMap.get(vo.getCreateBy()))
                    ? userMap.get(vo.getCreateBy()).getUserName() : StringUtils.EMPTY);
        }
        vo.setBusinessStaffName(vo.getBusinessManagerName());
        // 获取锁定时间
        if (StringUtils.isNotBlank(vo.getBusinessManagerName()))
        {
            JbRules one = jbRulesService.getOne(Wrappers.lambdaQuery(JbRules.class).eq(JbRules::getRulesCode, Constants.DEPT_HIGHSEAS));
            JbDeptHighseasRulesJson bean = BeanUtil.toBean(one.getExecutionContent(), JbDeptHighseasRulesJson.class);
            Integer day = bean.getNotTrading().getDay();
            Date transferCustomerTime = byId.getTransferCustomerTime();
            if (ObjectUtils.isNotEmpty(day) && ObjectUtils.isNotEmpty(transferCustomerTime))
            {
                Date date = DateUtils.dateAddDay(transferCustomerTime, day);
                String s = DateUtils.parseDateToStr(DateUtils.YYYY_MM_DD, date);
                vo.setBusinessManagerName(String.format("%s (已锁定，保护到期时间%s)", vo.getBusinessManagerName(), s));
            }
        }

        List<JbFollowupRecord> jbFollowupRecords = jbFollowupRecordService.list(Wrappers.lambdaQuery(JbFollowupRecord.class)
                .eq(JbFollowupRecord::getCustomerId, id)
                .eq(JbFollowupRecord::getDataType, Constants.PUBLIC_NUMBER_0)
                .ge(JbFollowupRecord::getFollowupTime, new Date()));
        if (ObjectUtils.isNotEmpty(jbFollowupRecords))
        {
            vo.setNextFollowUpTime(jbFollowupRecords.get(0).getFollowupTime());
        }
        // 区域名称
        if (StringUtils.isNotBlank(byId.getLocalArea()))
        {
            DivisionsCode code = new DivisionsCode();
            code.setCode(byId.getLocalArea());
            List<DivisionsCodeAllVo> allByCode = divisionsCodeService.findAllByCode(code);
            if (ObjectUtils.isNotEmpty(allByCode))
            {
                DivisionsCodeAllVo divisionsCodeAllVo = allByCode.get(0);
                vo.setLocalArea(divisionsCodeAllVo.getProvincesName() + divisionsCodeAllVo.getCitiesName() + divisionsCodeAllVo.getAreasName() + divisionsCodeAllVo.getStreetsName());
            }
        }
        // 获取最新的作物结构
        vo.setCropStructures(cropStructureList(id));
        JbFavoriteTable one = jbFavoriteTableService.getOne(Wrappers.lambdaQuery(JbFavoriteTable.class)
                .eq(JbFavoriteTable::getRelatedId, id).eq(JbFavoriteTable::getType, Constants.PUBLIC_NUMBER_2), false);
        if (ObjectUtils.isNotEmpty(one))
        {
            vo.setFavoriteId(one.getId());
        }
        // 订单金额
        QueryWrapper<JbOrder> orderWrapper = new QueryWrapper();
        orderWrapper.select(" sum(order_total_amount) as orderTotalAmount" +
                ",SUM(received_amount) as receivedAmount,count(1) as customerId ");
        orderWrapper.lambda().eq(JbOrder::getCustomerId, id)
                .eq(JbOrder::getIsProcessEnd, Constants.PUBLIC_NUMBER_1);//财务审批完的订单
        JbOrder jbOrderOne = jbOrderService.getOne(orderWrapper, false);
        if (ObjectUtils.isNotEmpty(jbOrderOne))
        {
            vo.setDealMoney(jbOrderOne.getOrderTotalAmount());
            vo.setRecycleMoney(jbOrderOne.getRealOrderAmount());
            vo.setDealOrder(jbOrderOne.getCustomerId());
        }
        QueryWrapper<JbRefund> refundWrapper = new QueryWrapper();
        refundWrapper.select(" SUM(refund_amount) as refundAmount ");
        refundWrapper.lambda().eq(JbRefund::getCustomerId, id);
        JbRefund refundOne = jbRefundService.getOne(refundWrapper, false);
        if (ObjectUtils.isNotEmpty(refundOne))
        {
            vo.setReturnMoney(refundOne.getRefundAmount());
        }

        return vo;
    }

    @Override
    public IPage<JbCustomerBelongToRecordVo> belongToRecord(IPage iPage, JbCustomer jbCustomer)
    {
        StringJoiner sql = new StringJoiner(" ").add("""
                SELECT
                	jc.id,jc.customer_name,jc.customer_type,jc.customer_status
                	,jcu.user_id,jcu.front_user_id,jcu.create_time,jcu.create_by
                	,(select user_name from sys_user su where su.user_id=jcu.user_id ) as userName
                	,(select user_name from sys_user su where su.user_id=jcu.front_user_id ) as frontUserName
                	,(select user_name from sys_user su where su.user_id=jcu.create_by ) as createUserName
                FROM
                	jb_customer jc
                	INNER JOIN jb_customer_user jcu ON jc.id = jcu.customer_id\s
                WHERE
                	jc.del_flag = '0'
                              
                """);
        sql.add(joSqlUtil.sqlIf(" and jc.id=#{id}", jbCustomer.getId()));
        String sqlStr = joSqlUtil.sqlJson(sql.toString(), jbCustomer);
        IPage<JbCustomerBelongToRecordVo> fn = joSqlUtil.jsonToEntity(baseMapper.pageJson(iPage, sqlStr),
                JbCustomerBelongToRecordVo.class);
        if (ObjectUtils.isNotEmpty(fn) && ObjectUtils.isNotEmpty(fn.getRecords()))
        {
            JbRules one = jbRulesService.getOne(Wrappers.lambdaQuery(JbRules.class).eq(JbRules::getRulesCode, Constants.DEPT_HIGHSEAS));
            JbDeptHighseasRulesJson bean = BeanUtil.toBean(one.getExecutionContent(), JbDeptHighseasRulesJson.class);
            Integer day = bean.getNotTrading().getDay();
            fn.getRecords().forEach(a ->
            {
                Date transferCustomerTime = a.getCreateTime();
                Date date = DateUtils.dateAddDay(transferCustomerTime, day);
                a.setStartTime(a.getCreateTime());
                a.setEndtTime(date);
            });
        }
        return fn;
    }

    @Override
    @Transactional
    public void deptHighseasAllocation(JbRules one)
    {
        log.info("===========部门公海自动分配规则执行-{}", LocalDateTime.now());
        long currentTime = System.currentTimeMillis();
        // 部门分配是自动轮询
        List<JbCustomer> list = list(Wrappers.lambdaQuery(JbCustomer.class).eq(JbCustomer::getDataType, Constants.PUBLIC_NUMBER_2));
        if (ObjectUtils.isNotEmpty(list))
        {
            String collect = list.stream().map(a -> a.getBusinessManagerId().toString()).distinct().collect(Collectors.joining(","));
            StringJoiner sql = new StringJoiner(" ").add("""
                        SELECT
                        	su.user_id,
                        	sd.dept_id,
                        	(if(sd.`level`<=3,sd.dept_id,SUBSTRING_INDEX( SUBSTRING_INDEX( sd.ancestors, ',', 4 ), ',',- 1 ))) AS levelDeptId\s
                        FROM
                        	sys_user su
                        	INNER JOIN sys_dept sd ON su.dept_id = sd.dept_id\s
                        WHERE
                        	su.del_flag = 0\s
                        	AND sd.del_flag = 0\s
                    """);
            sql.add(String.format("AND su.user_id in (%s)", collect));
            // 获取业务经理的第几层级id，现在获取第三层级部门id，上级部门id是小组
            List<SysUserVo> sysDeptList = joSqlUtil.jsonToEntity(baseMapper.findJson(sql.toString()), SysUserVo.class);
            if (ObjectUtils.isEmpty(sysDeptList)) return;
            Map<Long, List<SysUserVo>> allUserDeptId = Maps.newHashMap();
            // 业务人员对应的部门id
            Map<Long, Long> userDeptLevel = sysDeptList.stream().collect(Collectors.toMap(SysUserVo::getUserId, SysUserVo::getLevelDeptId));
            // 查询第几层级部门下的所有人
            List<Long> deptLevel = sysDeptList.stream().map(a -> a.getLevelDeptId()).distinct().collect(Collectors.toList());
            sql = new StringJoiner(" ").add("""
                    SELECT
                    	su.user_id,
                    	su.dept_id,
                    	(if(sd.`level`<=3,sd.dept_id,SUBSTRING_INDEX( SUBSTRING_INDEX( sd.ancestors, ',', 4 ), ',',- 1 ))) AS levelDeptId\s
                    FROM
                    	sys_user su
                    	INNER JOIN sys_dept sd ON su.dept_id = sd.dept_id\s
                    WHERE
                    	su.del_flag = 0\s
                    	AND sd.del_flag = 0\s
                        	and (
                    """);
            for (int i = 0; i < deptLevel.size(); i++)
            {
                if (i > 0)
                {
                    sql.add(" or ");
                }
                sql.add(String.format("FIND_IN_SET(%s,ancestors) or sd.dept_id=%s", deptLevel.get(i), deptLevel.get(i)));
            }
            sql.add(")");
            // 按部门排序，在按用户id 排序，，作用：按一个部门下的所有人分配
            sql.add(" order by su.dept_id,su.user_id");
            List<SysUserVo> allList = joSqlUtil.jsonToEntity(baseMapper.findJson(sql.toString()), SysUserVo.class);
            if (ObjectUtils.isEmpty(allList))
            {
                return;
            }
            allUserDeptId = allList.stream().collect(Collectors.groupingBy(SysUserVo::getLevelDeptId));
            // 要查询客户轮询的id
            List<Long> deptIds = Lists.newArrayList();
            // 处理每个部门公海客户，轮询分配业务经理
            for (JbCustomer customer : list)
            {
                Long levelDeptid = userDeptLevel.get(customer.getBusinessManagerId());
                customer.setDepartmentId(null);
                if (ObjectUtils.isNotEmpty(levelDeptid))
                {
                    deptIds.add(levelDeptid);
                    customer.setDepartmentId(levelDeptid);
                }
            }
            // 获取轮询过的数据
            List<JbOpportunityPolling> polling = jbOpportunityPollingService.list(Wrappers.lambdaQuery(JbOpportunityPolling.class)
                    .eq(JbOpportunityPolling::getDataType, Constants.PUBLIC_NUMBER_2)
                    .in(JbOpportunityPolling::getDeptId, deptIds));
            // 轮询过的数据，按部门分配
            Map<Long, List<JbOpportunityPolling>> mapPolling = polling.stream().collect(Collectors.groupingBy(JbOpportunityPolling::getDeptId));
            // 客户按部门分组
            Map<Long, List<JbCustomer>> mapCustomer = list.stream().filter(a -> ObjectUtils.isNotEmpty(a.getDepartmentId())).collect(Collectors.groupingBy(JbCustomer::getDepartmentId));
            // 添加轮询记录的数组
            List<JbOpportunityPolling> addPollingList = Lists.newArrayList();
            JbRules jbRules = jbRulesService.getOne(Wrappers.lambdaQuery(JbRules.class).eq(JbRules::getRulesCode, Constants.DEPT_HIGHSEAS_ALLOCATION));
            // 按部门，分别数据那些数据，轮询那些用户数据
            for (Map.Entry<Long, List<JbCustomer>> entry : mapCustomer.entrySet())
            {
                setCustomer(entry.getValue(), mapPolling.get(entry.getKey()), allUserDeptId.get(entry.getKey()), addPollingList, jbRules);
            }
            // 添加部门轮询的数据
            if (ObjectUtils.isNotEmpty(addPollingList))
            {
                // 先删除处理部门的轮询数据
                jbOpportunityPollingService.remove(Wrappers.lambdaQuery(JbOpportunityPolling.class)
                        .eq(JbOpportunityPolling::getDataType, Constants.PUBLIC_NUMBER_2)
                        .in(JbOpportunityPolling::getDeptId, deptIds));
                jbOpportunityPollingService.saveBatch(addPollingList);
            }
        }
        log.info("===========部门公海自动分配规则执行结束-{},{}", LocalDateTime.now(), System.currentTimeMillis() - currentTime);
    }

    @Override
    public List<JbCustomerCropStructureStatistics> cropStructure(Long id)
    {
        // 获取作物结构
        //财务审批完的订单
        StringJoiner sql = new StringJoiner(" ").add("""
                SELECT
                	jccs.id,
                	jccs.crop_year,
                	jccs.crop_variety,
                	jccs.crop_cost,
                	( SELECT GROUP_CONCAT( jbp.crop_name SEPARATOR ',' ) FROM jb_crop_variety jbp WHERE FIND_IN_SET( jbp.id, jccs.crop_variety ) > 0 ) AS cropVarietyName,
                	( SELECT SUM( jo.order_total_amount ) FROM jb_order jo WHERE jo.del_flag = 0 and jo.is_process_end='1' AND YEAR ( apply_time )= jccs.crop_year 
                	 and jo.customer_id=jccs.customer_id) AS orderTotal\s
                FROM
                	jb_customer_crop_structure jccs\s
                WHERE
                	 del_flag = 0\s
                	AND jccs.crop_type =1\s
                    """);
        sql.add(String.format(" AND jccs.customer_id = %s", id));
        // 获取业务经理的第几层级id，现在获取第三层级部门id，上级部门id是小组
        List<JbCustomerCropStructureStatistics> cropStructureVoList = joSqlUtil.jsonToEntity(baseMapper.findJson(sql.toString()), JbCustomerCropStructureStatistics.class);
        if (ObjectUtils.isNotEmpty(cropStructureVoList))
        {
            for (JbCustomerCropStructureStatistics a : cropStructureVoList)
            {
                if (ObjectUtils.isEmpty(a.getOrderTotal()))
                {
                    a.setOrderTotal(BigDecimal.ZERO);
                }
                if (StringUtils.isNotBlank(a.getCropCost()))
                {
                    BigDecimal divide = a.getOrderTotal().divide(new BigDecimal(a.getCropCost()), 2, BigDecimal.ROUND_HALF_UP).multiply(new BigDecimal(100));
                    a.setPercentage(divide.toString());
                } else
                {
                    a.setPercentage("100");
                }

            }
        }
        return cropStructureVoList;
    }

    @Override
    public List<JbCustomerSalesStatistics> saleScale(Long id)
    {
        // 获取作物结构
        // 财务审批完的订单
        StringJoiner sql = new StringJoiner(" ").add("""
                SELECT
                	jccs.id,
                	jccs.crop_year,
                	jccs.main_products,
                	jccs.sales_volume,
                	( SELECT GROUP_CONCAT( jbp.crop_name SEPARATOR ',' ) FROM jb_crop_variety jbp WHERE FIND_IN_SET( jbp.id, jccs.main_products ) > 0 ) AS cropVarietyName,
                	(
                	SELECT
                		SUM( jo.order_total_amount )\s
                	FROM
                		jb_order jo\s
                	WHERE
                		jo.del_flag = 0\s
                		and jo.is_process_end='1'
                		AND YEAR ( apply_time )= jccs.crop_year\s
                		AND jo.customer_id = jccs.customer_id\s
                	) AS orderTotal\s
                FROM
                	jb_customer_crop_structure jccs\s
                WHERE
                	jccs.del_flag = 0\s
                	AND jccs.crop_type = 2\s
                    """);
        sql.add(String.format(" AND jccs.customer_id = %s", id));
        // 获取业务经理的第几层级id，现在获取第三层级部门id，上级部门id是小组
        List<JbCustomerSalesStatistics> cropStructureVoList = joSqlUtil.jsonToEntity(baseMapper.findJson(sql.toString()), JbCustomerSalesStatistics.class);
        if (ObjectUtils.isNotEmpty(cropStructureVoList))
        {
            for (JbCustomerSalesStatistics a : cropStructureVoList)
            {
                if (ObjectUtils.isEmpty(a.getOrderTotal()))
                {
                    a.setOrderTotal(BigDecimal.ZERO);
                }
                if (StringUtils.isNotBlank(a.getSalesVolume()))
                {
                    BigDecimal divide = a.getOrderTotal().divide(new BigDecimal(a.getSalesVolume()), 2, BigDecimal.ROUND_HALF_UP).multiply(new BigDecimal(100));
                    a.setPercentage(divide.toString());
                } else
                {
                    a.setPercentage("100");
                }
            }
        }
        return cropStructureVoList;
    }

    @Override
    public List<JbOrder> orderAnalysis(Long id, String year)
    {
        return null;
    }

    @Override
    public IPage<JbOrder> orderRecord(IPage iPage, Long id, String year)
    {
        StringJoiner sql = new StringJoiner(" ").add("""
                SELECT
                	id,
                	order_number,
                	customer_id,
                	customer_name,
                	process_number,
                	order_total_amount,
                	order_status,
                	(received_amount+deposit_amount) as receivedAmount,
                	create_time\s
                FROM
                	jb_order\s
                WHERE
                	del_flag = 0\s
                """);
        sql.add(joSqlUtil.sqlIf(String.format(" AND customer_id =%s", id), id));
        sql.add(joSqlUtil.sqlIf(String.format(" AND YEAR ( create_time )=%s", year), year));
        return joSqlUtil.jsonToEntity(baseMapper.pageJson(iPage, sql.toString()), JbOrder.class);
    }

    @Override
    public IPage<JbCustomerProductStatistics> orderAnalysisProduct(Long id, String year, PageParam page)
    {
        StringJoiner sql = new StringJoiner(" ").add("""
                SELECT
                	jc.id,

                	jc.commodity_name as name,
                	SUM( joc.subtotal ) AS money,
                	count( 1 ) AS amount\s
                FROM
                	jb_order jo
                	INNER JOIN jb_order_commodity joc ON jo.id = joc.order_id
        
                	INNER JOIN jb_commodity jc ON joc.commodity_id = jc.id\s
                WHERE
                	jo.del_flag = 0\s
                	AND joc.del_flag = 0\s
                	AND jc.del_flag = 0\s
                	and jo.is_process_end='1'
                """);
        sql.add(String.format(" AND jo.customer_id = %s", id));
        sql.add(joSqlUtil.sqlIf(String.format(" AND YEAR ( jo.create_time )=%s", year), year));
        sql.add(" GROUP BY jc.id ORDER BY money DESC");
        IPage<JbCustomerProductStatistics> pageVo = joSqlUtil.jsonToEntity(baseMapper.pageJson(page.b(), sql.toString()), JbCustomerProductStatistics.class);
        if (ObjectUtils.isNotEmpty(pageVo) && ObjectUtils.isNotEmpty(pageVo.getRecords()))
        {
            for (int i = 0; i < pageVo.getRecords().size(); i++)
            {
                pageVo.getRecords().get(i).setRanking(getRanking(i, page));
            }
        }
        return pageVo;
    }

    /**
     * 获取结果集的排序
     *
     * @param number
     * @param page
     * @return
     */
    private int getRanking(int number, PageParam page)
    {
        return (page.getPageNum() * page.getPageSize()) - page.getPageSize() + number + 1;
    }

    @Override
    public List<JbCustomerMonthStatistics> orderAnalysisMonth(Long id, Integer year, String orderBy)
    {
        orderBy = StringUtils.isBlank(orderBy) ? " desc" : orderBy;
        // 本年
        List<JbCustomerMonthStatistics> jbCustomerMonthStatistics = getData(id, year, orderBy);
        // 上一年
        List<JbCustomerMonthStatistics> upData = getData(id, year - 1, orderBy);

        if (ObjectUtils.isNotEmpty(jbCustomerMonthStatistics))
        {
            Map<String, BigDecimal> monthMaps = Maps.newHashMap();
            if (ObjectUtils.isNotEmpty(upData))
            {
                monthMaps = upData.stream().collect(Collectors.toMap(JbCustomerMonthStatistics::getYearMonth, JbCustomerMonthStatistics::getMoney));
            }
            for (JbCustomerMonthStatistics a : jbCustomerMonthStatistics)
            {
                if (ObjectUtils.isEmpty(a.getAmount()))
                {
                    a.setAmount(Constants.PUBLIC_NUMBER_0);
                }
                if (ObjectUtils.isEmpty(a.getMoney()))
                {
                    a.setMoney(BigDecimal.ZERO);
                }
                BigDecimal upBigDecimal = monthMaps.get(a.getYearMonth());
                if (ObjectUtils.isNotEmpty(upBigDecimal))
                {
                    // 环比增长率 =（本期数－上期数）/ 上期数 ×100%
                    BigDecimal divide = (a.getMoney().subtract(upBigDecimal)).divide(upBigDecimal, 2, BigDecimal.ROUND_HALF_UP).multiply(new BigDecimal(100));
                    a.setRateOfIncrease(divide.toString());
                } else
                {
                    a.setRateOfIncrease("100");
                }
            }
        }
        return jbCustomerMonthStatistics;
    }

    private List<JbCustomerMonthStatistics> getData(Long id, Integer year, String orderBy)
    {
        //财务审批完的订单
        StringJoiner sql = new StringJoiner(" ").add("""
                SELECT
                	SUM(jo.order_total_amount ) AS money,
                	SUM(jo.quantity) AS amount,
                	DATE_FORMAT( jo.create_time, '%Y-%m' ) AS yearMonth\s
                FROM
                	jb_order jo\s
                WHERE
                	jo.del_flag = 0 and jo.is_process_end='1'\s
                """);
        sql.add(String.format(" AND jo.customer_id = %s", id));
        sql.add(joSqlUtil.sqlIf(String.format(" AND YEAR ( jo.create_time )=%s", year), year));
        sql.add(String.format(" GROUP BY yearMonth order by money %s", orderBy));
        List<JbCustomerMonthStatistics> jbCustomerMonthStatistics = joSqlUtil.jsonToEntity(baseMapper.findJson(sql.toString()), JbCustomerMonthStatistics.class);
        return jbCustomerMonthStatistics;
    }

    @Override
    public Integer customerIsExist(String phone)
    {
        StringJoiner sql = new StringJoiner(" ").add("""
                SELECT
                	jc.customer_name\s
                	,su.user_name
                FROM
                	jb_customer jc
                	INNER JOIN jb_order jo ON jc.id = jo.customer_id\s
                	INNER JOIN sys_user su on jc.business_manager_id=su.user_id
                WHERE
                	jc.del_flag = 0\s
                	AND jo.del_flag = 0\s
                	AND su.del_flag = 0\s
                """);
        sql.add(String.format(" AND jc.phone_number = %s", phone));
        sql.add(" ORDER BY jo.id ASC LIMIT 1");
        List<SysUser> jbUser = joSqlUtil.jsonToEntity(baseMapper.findJson(sql.toString()), SysUser.class);
        if (ObjectUtils.isNotEmpty(jbUser))
        {
            SysUser customer = jbUser.get(0);
            if (ObjectUtils.isNotEmpty(customer) && StringUtils.isNotBlank(customer.getUserName()))
            {
                throw new ServiceException(String.format(BusinessErrorEnum.CODE_ERROR_20016.getMsg(), customer.getUserName())
                        , BusinessErrorEnum.CODE_ERROR_20016.getCode());
            }
        }
        return null;
    }

    @Override
    public List<JbCustomerField> setFieldList()
    {
        LoginUser loginUser = getLoginUser();
        List<JbCustomerField> list = jbCustomerFieldService.list(Wrappers.lambdaQuery(JbCustomerField.class)
                .eq(JbCustomerField::getCreateBy, loginUser.getUserId())
        );
        return list;
    }

    @Override
    public Boolean setFieldSave(List<JbCustomerField> jbCustomerFields)
    {
        LoginUser loginUser = getLoginUser();
        jbCustomerFieldService.remove(Wrappers.lambdaQuery(JbCustomerField.class).eq(JbCustomerField::getCreateBy, loginUser.getUserId()));
        for (int i = 0; i < jbCustomerFields.size(); i++)
        {
            jbCustomerFields.get(i).setFieldSort(i + 1);
            jbCustomerFields.get(i).setCreateBy(loginUser.getUserId());
            jbCustomerFields.get(i).setCreateTime(new Date());
        }
        return jbCustomerFieldService.saveBatch(jbCustomerFields);
    }

    @Override
    public Boolean fastSearchSave(JbCustomerFastSearch jbCustomerFastSearch)
    {
        return jbCustomerFastSearchService.saveOrUpdate(jbCustomerFastSearch);
    }

    @Override
    public Boolean fastTopUp(Long id)
    {
        jbCustomerFastSearchService.update(Wrappers.lambdaUpdate(JbCustomerFastSearch.class)
                .eq(JbCustomerFastSearch::getCreateBy, getUserId())
                .eq(JbCustomerFastSearch::getFastTopUp, Constants.PUBLIC_NUMBER_0)
                .set(JbCustomerFastSearch::getFastTopUp, null));

        JbCustomerFastSearch jbCustomerFastSearch = new JbCustomerFastSearch();
        jbCustomerFastSearch.setId(id);
        jbCustomerFastSearch.setFastTopUp(Constants.PUBLIC_NUMBER_0);
        return jbCustomerFastSearchService.updateById(jbCustomerFastSearch);
    }

    @Override
    public Boolean fastSearchDel(Long id)
    {
        return jbCustomerFastSearchService.removeById(id);
    }

    @Override
    public List<JbCustomerFastSearch> fastSearchList()
    {
        LoginUser loginUser = getLoginUser();
        List<JbCustomerFastSearch> list = jbCustomerFastSearchService.list(Wrappers.lambdaQuery(JbCustomerFastSearch.class)
                .eq(JbCustomerFastSearch::getCreateBy, loginUser.getUserId())
                .orderByDesc(JbCustomerFastSearch::getTopUpTime)
                .orderByDesc(JbCustomerFastSearch::getId));
        return list;
    }

    @Override
    public JbCustomerFastSearch fastSearchInfo(Long id)
    {
        return jbCustomerFastSearchService.getById(id);
    }

    @Override
    public JbCustomerOverViewVo detailsMore(Long id)
    {
        JbCustomer byId = this.getById(id);
        JbCustomerOverViewVo vo = new JbCustomerOverViewVo();
        BeanUtils.copyProperties(byId, vo);
        SysUser one = sysUserService.getOne(Wrappers.lambdaQuery(SysUser.class)
                .eq(SysUser::getUserId, byId.getBusinessManagerId())
                .select(SysUser::getUserName));
        vo.setBusinessManagerName(Optional.ofNullable(one).map(a -> a.getUserName()).orElse(null));
        // 跟进记录
        long count = jbFollowupRecordService.count(Wrappers.lambdaQuery(JbFollowupRecord.class)
                .eq(JbFollowupRecord::getDataType, Constants.PUBLIC_NUMBER_1)
                .eq(JbFollowupRecord::getCustomerId, id));
        vo.setFollowUpRecordNumber(count);
        // 归属记录
        long belongToNumber = jbCustomerUserService.count(Wrappers.lambdaQuery(JbCustomerUser.class)
                .eq(JbCustomerUser::getCustomerId, id));
        vo.setBelongToNumber(belongToNumber);
        // 订单记录
        long orderCount = jbOrderService.count(Wrappers.lambdaQuery(JbOrder.class).eq(JbOrder::getCustomerId, id));
        vo.setOrderRecordNumber(orderCount);
        // 操作日志
        long opeLogNumber = jbBusinessOperRecordService.count(Wrappers.lambdaQuery(JbBusinessOperRecord.class).eq(JbBusinessOperRecord::getModuleCode, BusinessOperModule.CUSTOMER_OPER.getCode())
                .eq(JbBusinessOperRecord::getRecordId, id));
        vo.setOpeLogNumber(opeLogNumber);
        // 退款记录
        long refundNumber = jbRefundService.count(Wrappers.lambdaQuery(JbRefund.class)
                .eq(JbRefund::getCustomerId, id));
        vo.setRefundNumber(refundNumber);
        return vo;
    }

    @Override
    @Transactional
    public Boolean importData(List<JbCustomerExcle> jbCustomerExcle)
    {
        // 验证jbCustomerExcle数据所有字段是否有空值
        long size = jbCustomerExcle.stream().filter(
                a -> StringUtils.isBlank(a.getCustomerName())
                        || StringUtils.isBlank(a.getCustomerType())
                        || StringUtils.isBlank(a.getOpportunityChannel())
                        || StringUtils.isBlank(a.getPhoneNumber())
                        || StringUtils.isBlank(a.getOpportunitySource())
                        || StringUtils.isBlank(a.getCustomerStatus())
                        || StringUtils.isBlank(a.getCustomerLabels())
                        || StringUtils.isBlank(a.getBusinessManagerName())
        ).count();
        if (size > 0)
        {
            throw new ServiceException("导入数据不能有空值！");
        }

        //TODO 2025年2月18日16:15:09 加上吧，另外遇见重复手机号跳过，不要终止导入
//        long count = jbCustomerExcle.stream().map(JbCustomerExcle::getPhoneNumber).distinct().count();
//        if (count != jbCustomerExcle.size())
//        {
//            throw new ServiceException("导入数据不能有重复手机号！");
//        }
        // todo 获取字段配数据匹配编号
        List<SysDictData> list = sysDictDataService.list(Wrappers.lambdaQuery(SysDictData.class)
                .select(SysDictData::getDictLabel, SysDictData::getDictValue, SysDictData::getDictType)
                .in(SysDictData::getDictType,
                        new String[]{"bus_customer_type", "bus_channel", "bus_source"
                                , "bus_customer_status", "bus_client_tag"}));
        // 把list按DictType分组，在按DictLabel分组
        Map<String, Map<String, String>> collect = list.stream().collect(Collectors.groupingBy(SysDictData::getDictType,
                Collectors.toMap(SysDictData::getDictLabel, SysDictData::getDictValue)));
        // todo 获取员工id
        List<String> userName = jbCustomerExcle.stream().map(JbCustomerExcle::getBusinessManagerName).collect(Collectors.toSet()).stream().toList();
        List<SysUser> userList = sysUserService.list(Wrappers.lambdaQuery(SysUser.class)
                .select(SysUser::getUserId, SysUser::getUserName)
                .in(SysUser::getUserName, userName));
        if (userName.size() != userList.size())
        {
            throw new ServiceException("导入数据业务经理名称和系统中不匹配！");
        }
        Map<String, Long> userMap = userList.stream().collect(Collectors.toMap(SysUser::getUserName, SysUser::getUserId));
        // todo 匹配封装数据
        List<JbCustomerDto> addList = Lists.newArrayList();
        jbCustomerExcle.forEach(a ->
        {
            JbCustomerDto dto = BeanUtil.toBean(a, JbCustomerDto.class);
            String customerType = collect.get("bus_customer_type").get(a.getCustomerType());
            String opportunityChannel = collect.get("bus_channel").get(a.getOpportunityChannel());
            String opportunitySource = collect.get("bus_source").get(a.getOpportunitySource());
            String customerStatus = collect.get("bus_customer_status").get(a.getCustomerStatus());
            String customerLabels = collect.get("bus_client_tag").get(a.getCustomerLabels());
            if (StringUtils.isBlank(customerType)
                    || StringUtils.isBlank(opportunityChannel) || StringUtils.isBlank(opportunitySource)
                    || StringUtils.isBlank(customerStatus) || StringUtils.isBlank(customerLabels))
            {
                throw new ServiceException("导入数据和字典数据不匹配！");
            }
            dto.setCustomerType(customerType);
            dto.setOpportunityChannel(opportunityChannel);
            dto.setOpportunitySource(opportunitySource);
            dto.setCustomerStatus(customerStatus);
            dto.setCustomerLabels(customerLabels);
            dto.setBusinessManagerId(userMap.get(a.getBusinessManagerName()));
            addList.add(dto);
        });
        // todo 数据操作
        addList.forEach(a -> {
            try
            {
                saveInfo(a);
            }catch (ServiceException exception)
            {
                log.error("导入数据失败：{}",a.getCustomerName(),exception);
            }
        });
        return true;
    }


    /**
     * 执行 匹配轮询用户
     *
     * @param jbCustomerList
     * @param pollingList
     * @param userVoList
     * @param addPollingList
     */
    private void setCustomer(List<JbCustomer> jbCustomerList, List<JbOpportunityPolling> pollingList, List<SysUserVo> userVoList
            , List<JbOpportunityPolling> addPollingList, JbRules jbRules)
    {
        if (ObjectUtils.isEmpty(userVoList))
        {
            return;
        }
        // 以前循环过的
        Map<Long, Long> userMap = Maps.newHashMap();
        List<JbOpportunityPolling> exit = Lists.newArrayList();
        if (ObjectUtils.isNotEmpty(pollingList))
        {
            for (JbOpportunityPolling exist : pollingList)
            {
                userMap.put(exist.getRelationId(), exist.getDeptId());
                exit.add(exist);
            }
        }
        // 过滤没有循环过的
        Queue<SysUserVo> sysUserVos = new LinkedList<>();
        for (SysUserVo sysUserVo : userVoList)
        {
            Long userId = sysUserVo.getUserId();
            Long l = userMap.get(userId);
            if (ObjectUtils.isEmpty(l))
            {
                sysUserVos.offer(sysUserVo);
            }
        }


        // 循环客户数据，处理分配轮询用户数据
        for (int i = 0; i < jbCustomerList.size(); i++)
        {
            JbCustomer customer = jbCustomerList.get(i);
            // 第一个客户找完，，第二个客户接着第第一个客户的的位置开始找匹配。
            // 验证客户是否符合规则，不符合规则，找到符合的用户赋值
            // 这个是排除以前轮询的数据，未轮询的人员
            SysUserVo poll = verifyUser(sysUserVos, customer, jbRules);
            if (ObjectUtils.isEmpty(poll))
            {
                exit = Lists.newArrayList();
                // 这个是新的人员没有通过验证，在全部里在轮询一遍
                userVoList.forEach(a -> sysUserVos.offer(a));
                poll = verifyUser(sysUserVos, customer, jbRules);
            }

            if (ObjectUtils.isEmpty(poll))
            {
                // 没有匹配上，走下个客户
                continue;
            }
            // 追加没有轮询过的用户id
            JbOpportunityPolling jbOpportunityPolling = new JbOpportunityPolling();
            jbOpportunityPolling.setDataType(Constants.PUBLIC_NUMBER_2);
            jbOpportunityPolling.setDeptId(poll.getLevelDeptId());
            jbOpportunityPolling.setRelationId(poll.getUserId());
            exit.add(jbOpportunityPolling);
            // 添加修改客户的信息列表

            JbCustomer updateCustomer = new JbCustomer();
            updateCustomer.setId(customer.getId());
            updateCustomer.setDataType(Constants.PUBLIC_NUMBER_0);
            updateCustomer.setBusinessManagerId(poll.getUserId());
            updateCustomer.setDataTypeTime(new Date());
            updateById(updateCustomer);
        }
        addPollingList.addAll(exit);
    }

    private SysUserVo verifyUser(Queue<SysUserVo> sysUserVos, JbCustomer jbCustomer, JbRules jbRules)
    {
        SysUserVo selectUserId = null;
        while (!sysUserVos.isEmpty())
        {
            SysUserVo poll = sysUserVos.poll(); // 获取并移除队列的第一个元素
            if (poll.getUserId().equals(jbCustomer.getBusinessManagerId()))
            {
                // 验证系统规则，前负责人在N天内不能领取
                JbCustomerTransferDto jbCustomerTransferDto = new JbCustomerTransferDto();
                List<Long> ids = Lists.newArrayList();
                ids.add(jbCustomer.getId());
                jbCustomerTransferDto.setIds(ids);
                jbCustomerTransferDto.setBusinessManagerId(poll.getUserId());
                List<JbCustomer> jbCustomers = Lists.newArrayList();
                jbCustomers.add(jbCustomer);
                try
                {
                    verifyRule(jbRules, jbCustomerTransferDto, jbCustomers);
                    // 验证通过，不需要在验证数据，因自己分给自己
                    selectUserId = poll;
                    break;
                } catch (Exception ex)
                {
                    // 不满足同一个客户，分配到自己的条件
                    continue;
                }

            }
            try
            {
                // 验证是否满足条件
                List<JbCustomer> jbCustomerList = Lists.newArrayList();
                jbCustomerList.add(jbCustomer);
                verifyCustomerNumber(jbRules, poll.getUserId(), jbCustomerList);
                selectUserId = poll;
                break;
            } catch (Exception ex)
            {
                // 客户数量和客户类型谁验证不通过
            }
        }
        return selectUserId;
    }


    /**
     * 获取客户编码
     *
     * @return
     */
    private String getCustomerCode()
    {
        int attemptCount = 20;
        String kh = Strings.EMPTY;
        for (int i = 0; i <= attemptCount; i++)
        {
            kh = DateUtils.generateSerialNumber("KH", 4);
            long count = this.count(Wrappers.lambdaQuery(JbCustomer.class).eq(JbCustomer::getCustomerCode, kh));
            if (count == 0)
            {
                break;
            }
            if (attemptCount == i)
            {
                throw new ServiceException();
            }
        }
        return kh;
    }

    /**
     * 设置操作日志
     *
     * @param jbCustomer
     * @param businessType
     */
    private void setBusinessOperRecord(JbCustomer jbCustomer, Integer businessType)
    {
        LoginUser loginUser = getLoginUser();
        StringBuilder content = new StringBuilder();
        content.append("客户归属");
        if (ObjectUtils.isNotEmpty(jbCustomer.getFrontBusinessManagerId()))
        {
            SysUser sysUser = sysUserService.selectUserById(jbCustomer.getBusinessManagerId());
            if (ObjectUtils.isNotEmpty(sysUser) && StringUtils.isNotBlank(sysUser.getUserName()))
            {
                content.append("由").append(sysUser.getUserName());
            }
        }
        if (ObjectUtils.isNotEmpty(jbCustomer.getBusinessManagerId()))
        {
            SysUser sysUser = sysUserService.selectUserById(jbCustomer.getBusinessManagerId());
            if (ObjectUtils.isNotEmpty(sysUser) && StringUtils.isNotBlank(sysUser.getUserName()))
            {
                content.append("变为").append(sysUser.getUserName());
            }
        }

        // 添加客户动态的标题
        JbBusinessOperRecord jbBusinessOperRecord = new JbBusinessOperRecord();
        jbBusinessOperRecord.setTitle("客户归属");
        jbBusinessOperRecord.setModuleName(BusinessOperModule.CUSTOMER_DYNAMIC.getInfo());
        jbBusinessOperRecord.setModuleCode(BusinessOperModule.CUSTOMER_DYNAMIC.getCode());
        jbBusinessOperRecord.setRecordId(jbCustomer.getId());
        jbBusinessOperRecord.setContent(content.toString());
        jbBusinessOperRecord.setBusinessType(businessType);
        jbBusinessOperRecord.setBusinessId(jbCustomer.getBusinessManagerId());
        jbBusinessOperRecord.setMethod(ServletUtils.getRequest().getRequestURI());
        jbBusinessOperRecord.setOperatorType(Constants.PUBLIC_NUMBER_1);
        jbBusinessOperRecord.setCreateName(loginUser.getUsername());
        jbBusinessOperRecordService.save(jbBusinessOperRecord);
    }

    /**
     * 设置操作日志
     *
     * @param jbCustomer
     * @param businessType
     */
    private void setBusinessOperRecordBatch(List<JbCustomer> jbCustomer, Integer businessType)
    {
        LoginUser loginUser = getLoginUser();
        List<Long> uid = Lists.newArrayList();
        jbCustomer.forEach(a ->
        {
            uid.add(a.getBusinessManagerId());
            uid.add(a.getFrontBusinessManagerId());
        });
        List<SysUser> list = sysUserService.list(Wrappers.lambdaQuery(SysUser.class).in(SysUser::getUserId, uid)
                .select(SysUser::getUserId, SysUser::getUserName));
        Map<Long, String> userMap = list.stream().collect(Collectors.toMap(SysUser::getUserId, SysUser::getUserName));
        List<JbBusinessOperRecord> addBatch = Lists.newArrayList();
        jbCustomer.forEach(a ->
        {
            StringBuilder content = new StringBuilder();
            content.append("客户归属");
            if (ObjectUtils.isNotEmpty(a.getFrontBusinessManagerId()))
            {
                String s = userMap.get(a.getFrontBusinessManagerId());
                if (StringUtils.isNotBlank(s))
                {
                    content.append("由").append(s);
                }
            }
            if (ObjectUtils.isNotEmpty(a.getBusinessManagerId()))
            {
                String s = userMap.get(a.getBusinessManagerId());
                if (StringUtils.isNotBlank(s))
                {
                    content.append("变为").append(s);
                }
            }

            // 添加客户动态的标题
            JbBusinessOperRecord jbBusinessOperRecord = new JbBusinessOperRecord();
            jbBusinessOperRecord.setTitle("客户归属");
            jbBusinessOperRecord.setModuleName(BusinessOperModule.CUSTOMER_DYNAMIC.getInfo());
            jbBusinessOperRecord.setModuleCode(BusinessOperModule.CUSTOMER_DYNAMIC.getCode());
            jbBusinessOperRecord.setRecordId(a.getId());
            jbBusinessOperRecord.setContent(content.toString());
            jbBusinessOperRecord.setBusinessType(businessType);
            jbBusinessOperRecord.setBusinessId(a.getBusinessManagerId());
            jbBusinessOperRecord.setMethod(ServletUtils.getRequest().getRequestURI());
            jbBusinessOperRecord.setOperatorType(Constants.PUBLIC_NUMBER_1);
            jbBusinessOperRecord.setCreateName(loginUser.getUsername());
            addBatch.add(jbBusinessOperRecord);
        });

        jbBusinessOperRecordService.saveBatch(addBatch);
    }

}
